Directive attributes part 1: Support parameters in bound attributes (dotnet/aspnetcore-tooling#597)
* Directive attributes part 1: Support parameters in bound attributes
* update
* Fix test
* feedback
* Updated design
* Do case sensitive comparison
* more
* Bug fix
\n\nCommit migrated from 9bbf240948
This commit is contained in:
parent
13397dd4d6
commit
5bad5de7ee
|
|
@ -47,6 +47,8 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
|
|
||||||
public IReadOnlyDictionary<string, string> Metadata { get; protected set; }
|
public IReadOnlyDictionary<string, string> Metadata { get; protected set; }
|
||||||
|
|
||||||
|
public virtual IReadOnlyList<BoundAttributeParameterDescriptor> BoundAttributeParameters { get; protected set; }
|
||||||
|
|
||||||
public bool HasErrors
|
public bool HasErrors
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Language
|
namespace Microsoft.AspNetCore.Razor.Language
|
||||||
|
|
@ -26,5 +27,11 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
public abstract IDictionary<string, string> Metadata { get; }
|
public abstract IDictionary<string, string> Metadata { get; }
|
||||||
|
|
||||||
public abstract RazorDiagnosticCollection Diagnostics { get; }
|
public abstract RazorDiagnosticCollection Diagnostics { get; }
|
||||||
|
|
||||||
|
public virtual IReadOnlyList<BoundAttributeParameterDescriptorBuilder> BoundAttributeParameters { get; }
|
||||||
|
|
||||||
|
public virtual void BindAttributeParameter(Action<BoundAttributeParameterDescriptorBuilder> configure)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,9 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
throw new ArgumentNullException(nameof(builder));
|
throw new ArgumentNullException(nameof(builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (builder.Metadata.ContainsKey(TagHelperMetadata.Common.PropertyName))
|
if (builder.Metadata.TryGetValue(TagHelperMetadata.Common.PropertyName, out var value))
|
||||||
{
|
{
|
||||||
return builder.Metadata[TagHelperMetadata.Common.PropertyName];
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -51,5 +51,35 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
builder.IndexerAttributeNamePrefix = attributeNamePrefix;
|
builder.IndexerAttributeNamePrefix = attributeNamePrefix;
|
||||||
builder.IndexerValueTypeName = valueTypeName;
|
builder.IndexerValueTypeName = valueTypeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SetPropertyName(this BoundAttributeParameterDescriptorBuilder builder, string propertyName)
|
||||||
|
{
|
||||||
|
if (builder == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(builder));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (propertyName == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(propertyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Metadata[TagHelperMetadata.Common.PropertyName] = propertyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPropertyName(this BoundAttributeParameterDescriptorBuilder builder)
|
||||||
|
{
|
||||||
|
if (builder == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(builder));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (builder.Metadata.TryGetValue(TagHelperMetadata.Common.PropertyName, out var value))
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.Linq;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Language
|
namespace Microsoft.AspNetCore.Razor.Language
|
||||||
{
|
{
|
||||||
|
|
@ -49,5 +50,26 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
var isIndexerNameMatch = TagHelperMatchingConventions.SatisfiesBoundAttributeIndexer(name, attribute);
|
var isIndexerNameMatch = TagHelperMatchingConventions.SatisfiesBoundAttributeIndexer(name, attribute);
|
||||||
return isIndexerNameMatch && attribute.IsIndexerBooleanProperty;
|
return isIndexerNameMatch && attribute.IsIndexerBooleanProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsDefaultKind(this BoundAttributeParameterDescriptor parameter)
|
||||||
|
{
|
||||||
|
if (parameter == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(parameter));
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Equals(parameter.Kind, TagHelperConventions.DefaultKind, StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPropertyName(this BoundAttributeParameterDescriptor parameter)
|
||||||
|
{
|
||||||
|
if (parameter == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(parameter));
|
||||||
|
}
|
||||||
|
|
||||||
|
parameter.Metadata.TryGetValue(TagHelperMetadata.Common.PropertyName, out var propertyName);
|
||||||
|
return propertyName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Razor.Language
|
||||||
|
{
|
||||||
|
public abstract class BoundAttributeParameterDescriptor : IEquatable<BoundAttributeParameterDescriptor>
|
||||||
|
{
|
||||||
|
protected BoundAttributeParameterDescriptor(string kind)
|
||||||
|
{
|
||||||
|
Kind = kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Kind { get; }
|
||||||
|
|
||||||
|
public bool IsEnum { get; protected set; }
|
||||||
|
|
||||||
|
public bool IsStringProperty { get; protected set; }
|
||||||
|
|
||||||
|
public bool IsBooleanProperty { get; protected set; }
|
||||||
|
|
||||||
|
public string Name { get; protected set; }
|
||||||
|
|
||||||
|
public string TypeName { get; protected set; }
|
||||||
|
|
||||||
|
public string Documentation { get; protected set; }
|
||||||
|
|
||||||
|
public string DisplayName { get; protected set; }
|
||||||
|
|
||||||
|
public IReadOnlyList<RazorDiagnostic> Diagnostics { get; protected set; }
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<string, string> Metadata { get; protected set; }
|
||||||
|
|
||||||
|
public bool HasErrors
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var errors = Diagnostics.Any(diagnostic => diagnostic.Severity == RazorDiagnosticSeverity.Error);
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return DisplayName ?? base.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(BoundAttributeParameterDescriptor other)
|
||||||
|
{
|
||||||
|
return BoundAttributeParameterDescriptorComparer.Default.Equals(this, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return Equals(obj as BoundAttributeParameterDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return BoundAttributeParameterDescriptorComparer.Default.GetHashCode(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// 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.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Razor.Language
|
||||||
|
{
|
||||||
|
public abstract class BoundAttributeParameterDescriptorBuilder
|
||||||
|
{
|
||||||
|
public abstract string Name { get; set; }
|
||||||
|
|
||||||
|
public abstract string TypeName { get; set; }
|
||||||
|
|
||||||
|
public abstract bool IsEnum { get; set; }
|
||||||
|
|
||||||
|
public abstract string Documentation { get; set; }
|
||||||
|
|
||||||
|
public abstract string DisplayName { get; set; }
|
||||||
|
|
||||||
|
public abstract IDictionary<string, string> Metadata { get; }
|
||||||
|
|
||||||
|
public abstract RazorDiagnosticCollection Diagnostics { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.Extensions.Internal;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Razor.Language
|
||||||
|
{
|
||||||
|
internal class BoundAttributeParameterDescriptorComparer : IEqualityComparer<BoundAttributeParameterDescriptor>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A default instance of the <see cref="BoundAttributeParameterDescriptorComparer"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly BoundAttributeParameterDescriptorComparer Default = new BoundAttributeParameterDescriptorComparer();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A default instance of the <see cref="BoundAttributeParameterDescriptorComparer"/> that does case-sensitive comparison.
|
||||||
|
/// </summary>
|
||||||
|
internal static readonly BoundAttributeParameterDescriptorComparer CaseSensitive =
|
||||||
|
new BoundAttributeParameterDescriptorComparer(caseSensitive: true);
|
||||||
|
|
||||||
|
private readonly StringComparer _stringComparer;
|
||||||
|
private readonly StringComparison _stringComparison;
|
||||||
|
|
||||||
|
private BoundAttributeParameterDescriptorComparer(bool caseSensitive = false)
|
||||||
|
{
|
||||||
|
if (caseSensitive)
|
||||||
|
{
|
||||||
|
_stringComparer = StringComparer.Ordinal;
|
||||||
|
_stringComparison = StringComparison.Ordinal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_stringComparer = StringComparer.OrdinalIgnoreCase;
|
||||||
|
_stringComparison = StringComparison.OrdinalIgnoreCase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool Equals(BoundAttributeParameterDescriptor descriptorX, BoundAttributeParameterDescriptor descriptorY)
|
||||||
|
{
|
||||||
|
if (object.ReferenceEquals(descriptorX, descriptorY))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptorX == null ^ descriptorY == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
string.Equals(descriptorX.Kind, descriptorY.Kind, StringComparison.Ordinal) &&
|
||||||
|
descriptorX.IsEnum == descriptorY.IsEnum &&
|
||||||
|
string.Equals(descriptorX.Name, descriptorY.Name, _stringComparison) &&
|
||||||
|
string.Equals(descriptorX.TypeName, descriptorY.TypeName, StringComparison.Ordinal) &&
|
||||||
|
string.Equals(descriptorX.Documentation, descriptorY.Documentation, StringComparison.Ordinal) &&
|
||||||
|
string.Equals(descriptorX.DisplayName, descriptorY.DisplayName, StringComparison.Ordinal) &&
|
||||||
|
Enumerable.SequenceEqual(
|
||||||
|
descriptorX.Metadata.OrderBy(propertyX => propertyX.Key, StringComparer.Ordinal),
|
||||||
|
descriptorY.Metadata.OrderBy(propertyY => propertyY.Key, StringComparer.Ordinal));
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual int GetHashCode(BoundAttributeParameterDescriptor descriptor)
|
||||||
|
{
|
||||||
|
if (descriptor == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
var hash = HashCodeCombiner.Start();
|
||||||
|
hash.Add(descriptor.Kind);
|
||||||
|
hash.Add(descriptor.Name, _stringComparer);
|
||||||
|
|
||||||
|
return hash.CombinedHash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -123,14 +123,20 @@
|
||||||
<data name="BindTagHelper_Element_Documentation" xml:space="preserve">
|
<data name="BindTagHelper_Element_Documentation" xml:space="preserve">
|
||||||
<value>Binds the provided expression to the '{0}' attribute and a change event delegate to the '{1}' attribute.</value>
|
<value>Binds the provided expression to the '{0}' attribute and a change event delegate to the '{1}' attribute.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="BindTagHelper_Element_Event_Documentation" xml:space="preserve">
|
||||||
|
<value>Specifies the event handler name to attach for change notifications for the value provided by the '{0}' attribute.</value>
|
||||||
|
</data>
|
||||||
<data name="BindTagHelper_Element_Format_Documentation" xml:space="preserve">
|
<data name="BindTagHelper_Element_Format_Documentation" xml:space="preserve">
|
||||||
<value>Specifies a format to convert the value specified by the '{0}' attribute. The format string can currently only be used with expressions of type <code>DateTime</code>.</value>
|
<value>Specifies a format to convert the value specified by the '{0}' attribute. The format string can currently only be used with expressions of type <code>DateTime</code>.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="BindTagHelper_Fallback_Documentation" xml:space="preserve">
|
<data name="BindTagHelper_Fallback_Documentation" xml:space="preserve">
|
||||||
<value>Binds the provided expression to an attribute and a change event, based on the naming of the bind attribute. For example: <code>bind-value-onchange="..."</code> will assign the current value of the expression to the 'value' attribute, and assign a delegate that attempts to set the value to the 'onchange' attribute.</value>
|
<value>Binds the provided expression to an attribute and a change event, based on the naming of the bind attribute. For example: <code>bind-value="..."</code> and <code>bind-value:event="onchange"</code> will assign the current value of the expression to the 'value' attribute, and assign a delegate that attempts to set the value to the 'onchange' attribute.</value>
|
||||||
|
</data>
|
||||||
|
<data name="BindTagHelper_Fallback_Event_Documentation" xml:space="preserve">
|
||||||
|
<value>Specifies the event handler name to attach for change notifications for the value provided by the '{0}' attribute.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="BindTagHelper_Fallback_Format_Documentation" xml:space="preserve">
|
<data name="BindTagHelper_Fallback_Format_Documentation" xml:space="preserve">
|
||||||
<value>Specifies a format to convert the value specified by the corresponding bind attribute. For example: <code>format-value="..."</code> will apply a format string to the value specified in <code>bind-value-...</code>. The format string can currently only be used with expressions of type <code>DateTime</code>.</value>
|
<value>Specifies a format to convert the value specified by the corresponding bind attribute. For example: <code>bind-value:format="..."</code> will apply a format string to the value specified in <code>bind-value="..."</code>. The format string can currently only be used with expressions of type <code>DateTime</code>.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ChildContentParameterName_Documentation" xml:space="preserve">
|
<data name="ChildContentParameterName_Documentation" xml:space="preserve">
|
||||||
<value>Specifies the parameter name for the '{0}' child content expression.</value>
|
<value>Specifies the parameter name for the '{0}' child content expression.</value>
|
||||||
|
|
|
||||||
|
|
@ -30,18 +30,25 @@ 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<TagHelperPropertyIntermediateNode>();
|
||||||
|
var parameterReferences = documentNode.FindDescendantReferences<TagHelperAttributeParameterIntermediateNode>();
|
||||||
|
|
||||||
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++)
|
||||||
{
|
{
|
||||||
parents.Add(references[i].Parent);
|
parents.Add(references[i].Parent);
|
||||||
}
|
}
|
||||||
|
for (var i = 0; i < parameterReferences.Count; i++)
|
||||||
|
{
|
||||||
|
parents.Add(parameterReferences[i].Parent);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var parent in parents)
|
foreach (var parent in parents)
|
||||||
{
|
{
|
||||||
ProcessDuplicates(parent);
|
ProcessDuplicates(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// First, collect all the non-parameterized bind or bind-* attributes.
|
||||||
|
var bindEntries = new Dictionary<string, BindEntry>();
|
||||||
for (var i = 0; i < references.Count; i++)
|
for (var i = 0; i < references.Count; i++)
|
||||||
{
|
{
|
||||||
var reference = references[i];
|
var reference = references[i];
|
||||||
|
|
@ -55,14 +62,60 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
|
|
||||||
if (node.TagHelper.IsBindTagHelper() && node.AttributeName.StartsWith("bind"))
|
if (node.TagHelper.IsBindTagHelper() && node.AttributeName.StartsWith("bind"))
|
||||||
{
|
{
|
||||||
// Workaround for https://github.com/aspnet/Blazor/issues/703
|
bindEntries[node.AttributeName] = new BindEntry(reference);
|
||||||
var rewritten = RewriteUsage(reference.Parent, node);
|
}
|
||||||
reference.Remove();
|
}
|
||||||
|
|
||||||
for (var j = 0; j < rewritten.Length; j++)
|
// Now collect all the parameterized attributes and store them along with their corresponding bind or bind-* attributes.
|
||||||
|
for (var i = 0; i < parameterReferences.Count; i++)
|
||||||
|
{
|
||||||
|
var parameterReference = parameterReferences[i];
|
||||||
|
var node = (TagHelperAttributeParameterIntermediateNode)parameterReference.Node;
|
||||||
|
|
||||||
|
if (!parameterReference.Parent.Children.Contains(node))
|
||||||
|
{
|
||||||
|
// This node was removed as a duplicate, skip it.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.TagHelper.IsBindTagHelper() && node.AttributeName.StartsWith("bind"))
|
||||||
|
{
|
||||||
|
if (!bindEntries.TryGetValue(node.AttributeNameWithoutParameter, out var entry))
|
||||||
{
|
{
|
||||||
reference.Parent.Children.Add(rewritten[j]);
|
// There is no corresponding bind node. Add a diagnostic and move on.
|
||||||
|
parameterReference.Parent.Diagnostics.Add(ComponentDiagnosticFactory.CreateBindAttributeParameter_MissingBind(
|
||||||
|
node.Source,
|
||||||
|
node.AttributeName));
|
||||||
}
|
}
|
||||||
|
else if (node.BoundAttributeParameter.Name == "event")
|
||||||
|
{
|
||||||
|
entry.BindEventNode = node;
|
||||||
|
}
|
||||||
|
else if (node.BoundAttributeParameter.Name == "format")
|
||||||
|
{
|
||||||
|
entry.BindFormatNode = node;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Unsupported bind attribute parameter. This can only happen if bound attribute descriptor
|
||||||
|
// is configured to expect a parameter other than 'event' and 'format'.
|
||||||
|
}
|
||||||
|
|
||||||
|
// We've extracted what we need from the parameterized bind node. Remove it.
|
||||||
|
parameterReference.Remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We now have all the info we need to rewrite the tag helper.
|
||||||
|
foreach (var entry in bindEntries)
|
||||||
|
{
|
||||||
|
var reference = entry.Value.BindNodeReference;
|
||||||
|
var rewritten = RewriteUsage(reference.Parent, entry.Value);
|
||||||
|
reference.Remove();
|
||||||
|
|
||||||
|
for (var j = 0; j < rewritten.Length; j++)
|
||||||
|
{
|
||||||
|
reference.Parent.Children.Add(rewritten[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -78,18 +131,42 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
{
|
{
|
||||||
// For each usage of the general 'fallback' bind tag helper, it could duplicate
|
// For each usage of the general 'fallback' bind tag helper, it could duplicate
|
||||||
// the usage of a more specific one. Look for duplicates and remove the fallback.
|
// the usage of a more specific one. Look for duplicates and remove the fallback.
|
||||||
var attribute = node.Children[i] as TagHelperPropertyIntermediateNode;
|
TagHelperDescriptor tagHelper = null;
|
||||||
|
string attributeName = null;
|
||||||
|
var attribute = node.Children[i];
|
||||||
|
if (attribute is TagHelperPropertyIntermediateNode propertyAttribute)
|
||||||
|
{
|
||||||
|
attributeName = propertyAttribute.AttributeName;
|
||||||
|
tagHelper = propertyAttribute.TagHelper;
|
||||||
|
}
|
||||||
|
else if (attribute is TagHelperAttributeParameterIntermediateNode parameterAttribute)
|
||||||
|
{
|
||||||
|
attributeName = parameterAttribute.AttributeName;
|
||||||
|
tagHelper = parameterAttribute.TagHelper;
|
||||||
|
}
|
||||||
if (attribute != null &&
|
if (attribute != null &&
|
||||||
attribute.TagHelper != null &&
|
tagHelper != null &&
|
||||||
attribute.TagHelper.IsFallbackBindTagHelper())
|
tagHelper.IsFallbackBindTagHelper())
|
||||||
{
|
{
|
||||||
for (var j = 0; j < node.Children.Count; j++)
|
for (var j = 0; j < node.Children.Count; j++)
|
||||||
{
|
{
|
||||||
var duplicate = node.Children[j] as TagHelperPropertyIntermediateNode;
|
TagHelperDescriptor duplicateTagHelper = null;
|
||||||
|
string duplicateAttributeName = null;
|
||||||
|
var duplicate = node.Children[j];
|
||||||
|
if (duplicate is TagHelperPropertyIntermediateNode duplicatePropertyAttribute)
|
||||||
|
{
|
||||||
|
duplicateAttributeName = duplicatePropertyAttribute.AttributeName;
|
||||||
|
duplicateTagHelper = duplicatePropertyAttribute.TagHelper;
|
||||||
|
}
|
||||||
|
else if (duplicate is TagHelperAttributeParameterIntermediateNode duplicateParameterAttribute)
|
||||||
|
{
|
||||||
|
duplicateAttributeName = duplicateParameterAttribute.AttributeName;
|
||||||
|
duplicateTagHelper = duplicateParameterAttribute.TagHelper;
|
||||||
|
}
|
||||||
if (duplicate != null &&
|
if (duplicate != null &&
|
||||||
duplicate.TagHelper != null &&
|
duplicateTagHelper != null &&
|
||||||
duplicate.TagHelper.IsBindTagHelper() &&
|
duplicateTagHelper.IsBindTagHelper() &&
|
||||||
duplicate.AttributeName == attribute.AttributeName &&
|
duplicateAttributeName == attributeName &&
|
||||||
!object.ReferenceEquals(attribute, duplicate))
|
!object.ReferenceEquals(attribute, duplicate))
|
||||||
{
|
{
|
||||||
// Found a duplicate - remove the 'fallback' in favor of the
|
// Found a duplicate - remove the 'fallback' in favor of the
|
||||||
|
|
@ -104,16 +181,28 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
// This is a workaround for a limitation where you can't write a tag helper that binds only
|
// This is a workaround for a limitation where you can't write a tag helper that binds only
|
||||||
// when a specific attribute is **not** present.
|
// when a specific attribute is **not** present.
|
||||||
if (attribute != null &&
|
if (attribute != null &&
|
||||||
attribute.TagHelper != null &&
|
tagHelper != null &&
|
||||||
attribute.TagHelper.IsInputElementFallbackBindTagHelper())
|
tagHelper.IsInputElementFallbackBindTagHelper())
|
||||||
{
|
{
|
||||||
for (var j = 0; j < node.Children.Count; j++)
|
for (var j = 0; j < node.Children.Count; j++)
|
||||||
{
|
{
|
||||||
var duplicate = node.Children[j] as TagHelperPropertyIntermediateNode;
|
TagHelperDescriptor duplicateTagHelper = null;
|
||||||
|
string duplicateAttributeName = null;
|
||||||
|
var duplicate = node.Children[j];
|
||||||
|
if (duplicate is TagHelperPropertyIntermediateNode duplicatePropertyAttribute)
|
||||||
|
{
|
||||||
|
duplicateAttributeName = duplicatePropertyAttribute.AttributeName;
|
||||||
|
duplicateTagHelper = duplicatePropertyAttribute.TagHelper;
|
||||||
|
}
|
||||||
|
else if (duplicate is TagHelperAttributeParameterIntermediateNode duplicateParameterAttribute)
|
||||||
|
{
|
||||||
|
duplicateAttributeName = duplicateParameterAttribute.AttributeName;
|
||||||
|
duplicateTagHelper = duplicateParameterAttribute.TagHelper;
|
||||||
|
}
|
||||||
if (duplicate != null &&
|
if (duplicate != null &&
|
||||||
duplicate.TagHelper != null &&
|
duplicateTagHelper != null &&
|
||||||
duplicate.TagHelper.IsInputElementBindTagHelper() &&
|
duplicateTagHelper.IsInputElementBindTagHelper() &&
|
||||||
duplicate.AttributeName == attribute.AttributeName &&
|
duplicateAttributeName == attributeName &&
|
||||||
!object.ReferenceEquals(attribute, duplicate))
|
!object.ReferenceEquals(attribute, duplicate))
|
||||||
{
|
{
|
||||||
// Found a duplicate - remove the 'fallback' input tag helper in favor of the
|
// Found a duplicate - remove the 'fallback' input tag helper in favor of the
|
||||||
|
|
@ -144,7 +233,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntermediateNode[] RewriteUsage(IntermediateNode parent, TagHelperPropertyIntermediateNode node)
|
private IntermediateNode[] RewriteUsage(IntermediateNode parent, BindEntry bindEntry)
|
||||||
{
|
{
|
||||||
// Bind works similarly to a macro, it always expands to code that the user could have written.
|
// Bind works similarly to a macro, it always expands to code that the user could have written.
|
||||||
//
|
//
|
||||||
|
|
@ -168,10 +257,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
// We also assume that the element will be treated as a component for now because
|
// We also assume that the element will be treated as a component for now because
|
||||||
// multiple passes handle 'special' tag helpers. We have another pass that translates
|
// multiple passes handle 'special' tag helpers. We have another pass that translates
|
||||||
// a tag helper node back into 'regular' element when it doesn't have an associated component
|
// a tag helper node back into 'regular' element when it doesn't have an associated component
|
||||||
|
var node = bindEntry.BindNode;
|
||||||
if (!TryComputeAttributeNames(
|
if (!TryComputeAttributeNames(
|
||||||
parent,
|
parent,
|
||||||
node,
|
bindEntry,
|
||||||
node.AttributeName,
|
|
||||||
out var valueAttributeName,
|
out var valueAttributeName,
|
||||||
out var changeAttributeName,
|
out var changeAttributeName,
|
||||||
out var expressionAttributeName,
|
out var expressionAttributeName,
|
||||||
|
|
@ -198,16 +287,20 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
// Look for a matching format node. If we find one then we need to pass the format into the
|
// Look for a matching format node. If we find one then we need to pass the format into the
|
||||||
// two nodes we generate.
|
// two nodes we generate.
|
||||||
IntermediateToken format = null;
|
IntermediateToken format = null;
|
||||||
|
if (bindEntry.BindFormatNode != null)
|
||||||
|
{
|
||||||
|
format = GetAttributeContent(bindEntry.BindFormatNode);
|
||||||
|
}
|
||||||
|
|
||||||
if (TryGetFormatNode(
|
if (TryGetFormatNode(
|
||||||
parent,
|
parent,
|
||||||
node,
|
node,
|
||||||
valueAttributeName,
|
valueAttributeName,
|
||||||
out var formatNode))
|
out var formatNode))
|
||||||
{
|
{
|
||||||
// Don't write the format out as its own attribute, just capture it as a string
|
// If there is a format- attribute present, add a warning to say that it's unsupported.
|
||||||
// or expression.
|
|
||||||
parent.Children.Remove(formatNode);
|
parent.Children.Remove(formatNode);
|
||||||
format = GetAttributeContent(formatNode);
|
parent.Diagnostics.Add(ComponentDiagnosticFactory.CreateBindAttribute_FormatNode_Unsupported(formatNode.Source));
|
||||||
}
|
}
|
||||||
|
|
||||||
var valueExpressionTokens = new List<IntermediateToken>();
|
var valueExpressionTokens = new List<IntermediateToken>();
|
||||||
|
|
@ -336,10 +429,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryParseBindAttribute(
|
private bool TryParseBindAttribute(
|
||||||
string attributeName,
|
BindEntry bindEntry,
|
||||||
out string valueAttributeName,
|
out string valueAttributeName,
|
||||||
out string changeAttributeName)
|
out string changeAttributeName)
|
||||||
{
|
{
|
||||||
|
var attributeName = bindEntry.BindNode.AttributeName;
|
||||||
valueAttributeName = null;
|
valueAttributeName = null;
|
||||||
changeAttributeName = null;
|
changeAttributeName = null;
|
||||||
|
|
||||||
|
|
@ -348,6 +442,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bindEntry.BindEventNode != null)
|
||||||
|
{
|
||||||
|
changeAttributeName = GetAttributeContent(bindEntry.BindEventNode)?.Content?.Trim('"');
|
||||||
|
}
|
||||||
|
|
||||||
if (attributeName == "bind")
|
if (attributeName == "bind")
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -369,8 +468,9 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
changeAttributeName = segments[2];
|
|
||||||
valueAttributeName = segments[1];
|
valueAttributeName = segments[1];
|
||||||
|
changeAttributeName = segments[2];
|
||||||
|
bindEntry.BindNode.Diagnostics.Add(ComponentDiagnosticFactory.CreateBindAttribute_UnsupportedFormat(bindEntry.BindNode.Source));
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -381,8 +481,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
// Attempts to compute the attribute names that should be used for an instance of 'bind'.
|
// Attempts to compute the attribute names that should be used for an instance of 'bind'.
|
||||||
private bool TryComputeAttributeNames(
|
private bool TryComputeAttributeNames(
|
||||||
IntermediateNode parent,
|
IntermediateNode parent,
|
||||||
TagHelperPropertyIntermediateNode node,
|
BindEntry bindEntry,
|
||||||
string attributeName,
|
|
||||||
out string valueAttributeName,
|
out string valueAttributeName,
|
||||||
out string changeAttributeName,
|
out string changeAttributeName,
|
||||||
out string expressionAttributeName,
|
out string expressionAttributeName,
|
||||||
|
|
@ -397,7 +496,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
|
|
||||||
// Even though some of our 'bind' tag helpers specify the attribute names, they
|
// Even though some of our 'bind' tag helpers specify the attribute names, they
|
||||||
// should still satisfy one of the valid syntaxes.
|
// should still satisfy one of the valid syntaxes.
|
||||||
if (!TryParseBindAttribute(attributeName, out valueAttributeName, out changeAttributeName))
|
if (!TryParseBindAttribute(bindEntry, out valueAttributeName, out changeAttributeName))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -408,6 +507,8 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
// generated to match a specific tag and has metadata that identify the attributes.
|
// generated to match a specific tag and has metadata that identify the attributes.
|
||||||
//
|
//
|
||||||
// We expect 1 bind tag helper per-node.
|
// We expect 1 bind tag helper per-node.
|
||||||
|
var node = bindEntry.BindNode;
|
||||||
|
var attributeName = node.AttributeName;
|
||||||
valueAttributeName = node.TagHelper.GetValueAttributeName() ?? valueAttributeName;
|
valueAttributeName = node.TagHelper.GetValueAttributeName() ?? valueAttributeName;
|
||||||
changeAttributeName = node.TagHelper.GetChangeAttributeName() ?? changeAttributeName;
|
changeAttributeName = node.TagHelper.GetChangeAttributeName() ?? changeAttributeName;
|
||||||
expressionAttributeName = node.TagHelper.GetExpressionAttributeName() ?? expressionAttributeName;
|
expressionAttributeName = node.TagHelper.GetExpressionAttributeName() ?? expressionAttributeName;
|
||||||
|
|
@ -630,7 +731,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IntermediateToken GetAttributeContent(TagHelperPropertyIntermediateNode node)
|
private static IntermediateToken GetAttributeContent(IntermediateNode node)
|
||||||
{
|
{
|
||||||
var template = node.FindDescendantNodes<TemplateIntermediateNode>().FirstOrDefault();
|
var template = node.FindDescendantNodes<TemplateIntermediateNode>().FirstOrDefault();
|
||||||
if (template != null)
|
if (template != null)
|
||||||
|
|
@ -674,5 +775,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class BindEntry
|
||||||
|
{
|
||||||
|
public BindEntry(IntermediateNodeReference bindNodeReference)
|
||||||
|
{
|
||||||
|
BindNodeReference = bindNodeReference;
|
||||||
|
BindNode = (TagHelperPropertyIntermediateNode)bindNodeReference.Node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntermediateNodeReference BindNodeReference { get; }
|
||||||
|
|
||||||
|
public TagHelperPropertyIntermediateNode BindNode { get; }
|
||||||
|
|
||||||
|
public TagHelperAttributeParameterIntermediateNode BindEventNode { get; set; }
|
||||||
|
|
||||||
|
public TagHelperAttributeParameterIntermediateNode BindFormatNode { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
new RazorDiagnosticDescriptor(
|
new RazorDiagnosticDescriptor(
|
||||||
$"{DiagnosticPrefix}9991",
|
$"{DiagnosticPrefix}9991",
|
||||||
() => "The attribute names could not be inferred from bind attribute '{0}'. Bind attributes should be of the form" +
|
() => "The attribute names could not be inferred from bind attribute '{0}'. Bind attributes should be of the form" +
|
||||||
"'bind', 'bind-value' or 'bind-value-change'",
|
"'bind' or 'bind-value' along with their corresponding optional parameters like 'bind-value:event', 'bind:format' etc.",
|
||||||
RazorDiagnosticSeverity.Error);
|
RazorDiagnosticSeverity.Error);
|
||||||
|
|
||||||
public static RazorDiagnostic CreateBindAttribute_InvalidSyntax(SourceSpan? source, string attribute)
|
public static RazorDiagnostic CreateBindAttribute_InvalidSyntax(SourceSpan? source, string attribute)
|
||||||
|
|
@ -332,5 +332,48 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
{
|
{
|
||||||
return RazorDiagnostic.Create(UnsupportedComponentImportContent, source ?? SourceSpan.Undefined);
|
return RazorDiagnostic.Create(UnsupportedComponentImportContent, source ?? SourceSpan.Undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static readonly RazorDiagnosticDescriptor BindAttributeParameter_MissingBind =
|
||||||
|
new RazorDiagnosticDescriptor(
|
||||||
|
$"{DiagnosticPrefix}10004",
|
||||||
|
() => "Could not find the non-parameterized bind attribute that corresponds to the attribute '{0}'.",
|
||||||
|
RazorDiagnosticSeverity.Error);
|
||||||
|
|
||||||
|
public static RazorDiagnostic CreateBindAttributeParameter_MissingBind(SourceSpan? source, string attribute)
|
||||||
|
{
|
||||||
|
var diagnostic = RazorDiagnostic.Create(
|
||||||
|
BindAttributeParameter_MissingBind,
|
||||||
|
source ?? SourceSpan.Undefined,
|
||||||
|
attribute);
|
||||||
|
return diagnostic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly RazorDiagnosticDescriptor BindAttribute_UnsupportedFormat =
|
||||||
|
new RazorDiagnosticDescriptor(
|
||||||
|
$"{DiagnosticPrefix}10005",
|
||||||
|
() => "Specifying event handlers in bind attributes are no longer supported. Specify it using the bind:event=... attribute instead.",
|
||||||
|
RazorDiagnosticSeverity.Warning);
|
||||||
|
|
||||||
|
public static RazorDiagnostic CreateBindAttribute_UnsupportedFormat(SourceSpan? source)
|
||||||
|
{
|
||||||
|
var diagnostic = RazorDiagnostic.Create(
|
||||||
|
BindAttribute_UnsupportedFormat,
|
||||||
|
source ?? SourceSpan.Undefined);
|
||||||
|
return diagnostic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly RazorDiagnosticDescriptor BindAttribute_FormatNode_Unsupported =
|
||||||
|
new RazorDiagnosticDescriptor(
|
||||||
|
$"{DiagnosticPrefix}10005",
|
||||||
|
() => "Specifying format using 'format-...' attributes are no longer supported. Specify it using the 'bind-...:format=...' attribute instead.",
|
||||||
|
RazorDiagnosticSeverity.Warning);
|
||||||
|
|
||||||
|
public static RazorDiagnostic CreateBindAttribute_FormatNode_Unsupported(SourceSpan? source)
|
||||||
|
{
|
||||||
|
var diagnostic = RazorDiagnostic.Create(
|
||||||
|
BindAttribute_FormatNode_Unsupported,
|
||||||
|
source ?? SourceSpan.Undefined);
|
||||||
|
return diagnostic;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
string indexerTypeName,
|
string indexerTypeName,
|
||||||
string documentation,
|
string documentation,
|
||||||
string displayName,
|
string displayName,
|
||||||
|
BoundAttributeParameterDescriptor[] parameterDescriptors,
|
||||||
Dictionary<string, string> metadata,
|
Dictionary<string, string> metadata,
|
||||||
RazorDiagnostic[] diagnostics)
|
RazorDiagnostic[] diagnostics)
|
||||||
: base(kind)
|
: base(kind)
|
||||||
|
|
@ -29,6 +30,7 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
IndexerTypeName = indexerTypeName;
|
IndexerTypeName = indexerTypeName;
|
||||||
Documentation = documentation;
|
Documentation = documentation;
|
||||||
DisplayName = displayName;
|
DisplayName = displayName;
|
||||||
|
BoundAttributeParameters = parameterDescriptors;
|
||||||
|
|
||||||
Metadata = metadata;
|
Metadata = metadata;
|
||||||
Diagnostics = diagnostics;
|
Diagnostics = diagnostics;
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
private readonly DefaultTagHelperDescriptorBuilder _parent;
|
private readonly DefaultTagHelperDescriptorBuilder _parent;
|
||||||
private readonly string _kind;
|
private readonly string _kind;
|
||||||
private readonly Dictionary<string, string> _metadata;
|
private readonly Dictionary<string, string> _metadata;
|
||||||
|
private List<DefaultBoundAttributeParameterDescriptorBuilder> _attributeParameterBuilders;
|
||||||
|
|
||||||
private RazorDiagnosticCollection _diagnostics;
|
private RazorDiagnosticCollection _diagnostics;
|
||||||
|
|
||||||
|
|
@ -73,6 +74,20 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void BindAttributeParameter(Action<BoundAttributeParameterDescriptorBuilder> configure)
|
||||||
|
{
|
||||||
|
if (configure == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(configure));
|
||||||
|
}
|
||||||
|
|
||||||
|
EnsureAttributeParameterBuilders();
|
||||||
|
|
||||||
|
var builder = new DefaultBoundAttributeParameterDescriptorBuilder(this, _kind);
|
||||||
|
configure(builder);
|
||||||
|
_attributeParameterBuilders.Add(builder);
|
||||||
|
}
|
||||||
|
|
||||||
public BoundAttributeDescriptor Build()
|
public BoundAttributeDescriptor Build()
|
||||||
{
|
{
|
||||||
var validationDiagnostics = Validate();
|
var validationDiagnostics = Validate();
|
||||||
|
|
@ -82,6 +97,19 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
diagnostics.UnionWith(_diagnostics);
|
diagnostics.UnionWith(_diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var parameters = Array.Empty<BoundAttributeParameterDescriptor>();
|
||||||
|
if (_attributeParameterBuilders != null)
|
||||||
|
{
|
||||||
|
// Attribute parameters are case-sensitive.
|
||||||
|
var parameterset = new HashSet<BoundAttributeParameterDescriptor>(BoundAttributeParameterDescriptorComparer.CaseSensitive);
|
||||||
|
for (var i = 0; i < _attributeParameterBuilders.Count; i++)
|
||||||
|
{
|
||||||
|
parameterset.Add(_attributeParameterBuilders[i].Build());
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters = parameterset.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
var descriptor = new DefaultBoundAttributeDescriptor(
|
var descriptor = new DefaultBoundAttributeDescriptor(
|
||||||
_kind,
|
_kind,
|
||||||
Name,
|
Name,
|
||||||
|
|
@ -92,6 +120,7 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
IndexerValueTypeName,
|
IndexerValueTypeName,
|
||||||
Documentation,
|
Documentation,
|
||||||
GetDisplayName(),
|
GetDisplayName(),
|
||||||
|
parameters,
|
||||||
new Dictionary<string, string>(Metadata),
|
new Dictionary<string, string>(Metadata),
|
||||||
diagnostics.ToArray());
|
diagnostics.ToArray());
|
||||||
|
|
||||||
|
|
@ -205,5 +234,13 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void EnsureAttributeParameterBuilders()
|
||||||
|
{
|
||||||
|
if (_attributeParameterBuilders == null)
|
||||||
|
{
|
||||||
|
_attributeParameterBuilders = new List<DefaultBoundAttributeParameterDescriptorBuilder>();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
// 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.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Razor.Language
|
||||||
|
{
|
||||||
|
internal class DefaultBoundAttributeParameterDescriptor : BoundAttributeParameterDescriptor
|
||||||
|
{
|
||||||
|
public DefaultBoundAttributeParameterDescriptor(
|
||||||
|
string kind,
|
||||||
|
string name,
|
||||||
|
string typeName,
|
||||||
|
bool isEnum,
|
||||||
|
string documentation,
|
||||||
|
string displayName,
|
||||||
|
Dictionary<string, string> metadata,
|
||||||
|
RazorDiagnostic[] diagnostics)
|
||||||
|
: base(kind)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
TypeName = typeName;
|
||||||
|
IsEnum = isEnum;
|
||||||
|
Documentation = documentation;
|
||||||
|
DisplayName = displayName;
|
||||||
|
|
||||||
|
Metadata = metadata;
|
||||||
|
Diagnostics = diagnostics;
|
||||||
|
|
||||||
|
IsStringProperty = typeName == typeof(string).FullName || typeName == "string";
|
||||||
|
IsBooleanProperty = typeName == typeof(bool).FullName || typeName == "bool";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Razor.Language
|
||||||
|
{
|
||||||
|
internal class DefaultBoundAttributeParameterDescriptorBuilder : BoundAttributeParameterDescriptorBuilder
|
||||||
|
{
|
||||||
|
private readonly DefaultBoundAttributeDescriptorBuilder _parent;
|
||||||
|
private readonly string _kind;
|
||||||
|
private readonly Dictionary<string, string> _metadata;
|
||||||
|
|
||||||
|
private RazorDiagnosticCollection _diagnostics;
|
||||||
|
|
||||||
|
public DefaultBoundAttributeParameterDescriptorBuilder(DefaultBoundAttributeDescriptorBuilder parent, string kind)
|
||||||
|
{
|
||||||
|
_parent = parent;
|
||||||
|
_kind = kind;
|
||||||
|
|
||||||
|
_metadata = new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Name { get; set; }
|
||||||
|
|
||||||
|
public override string TypeName { get; set; }
|
||||||
|
|
||||||
|
public override bool IsEnum { get; set; }
|
||||||
|
|
||||||
|
public override string Documentation { get; set; }
|
||||||
|
|
||||||
|
public override string DisplayName { get; set; }
|
||||||
|
|
||||||
|
public override IDictionary<string, string> Metadata => _metadata;
|
||||||
|
|
||||||
|
public override RazorDiagnosticCollection Diagnostics
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_diagnostics == null)
|
||||||
|
{
|
||||||
|
_diagnostics = new RazorDiagnosticCollection();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _diagnostics;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoundAttributeParameterDescriptor Build()
|
||||||
|
{
|
||||||
|
var validationDiagnostics = Validate();
|
||||||
|
var diagnostics = new HashSet<RazorDiagnostic>(validationDiagnostics);
|
||||||
|
if (_diagnostics != null)
|
||||||
|
{
|
||||||
|
diagnostics.UnionWith(_diagnostics);
|
||||||
|
}
|
||||||
|
var descriptor = new DefaultBoundAttributeParameterDescriptor(
|
||||||
|
_kind,
|
||||||
|
Name,
|
||||||
|
TypeName,
|
||||||
|
IsEnum,
|
||||||
|
Documentation,
|
||||||
|
GetDisplayName(),
|
||||||
|
new Dictionary<string, string>(Metadata),
|
||||||
|
diagnostics.ToArray());
|
||||||
|
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetDisplayName()
|
||||||
|
{
|
||||||
|
if (DisplayName != null)
|
||||||
|
{
|
||||||
|
return DisplayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $":{Name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<RazorDiagnostic> Validate()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(Name))
|
||||||
|
{
|
||||||
|
var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributeParameterNullOrWhitespace(_parent.Name);
|
||||||
|
yield return diagnostic;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var character in Name)
|
||||||
|
{
|
||||||
|
if (char.IsWhiteSpace(character) || HtmlConventions.InvalidNonWhitespaceHtmlCharacters.Contains(character))
|
||||||
|
{
|
||||||
|
var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributeParameterName(
|
||||||
|
_parent.Name,
|
||||||
|
Name,
|
||||||
|
character);
|
||||||
|
|
||||||
|
yield return diagnostic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1716,6 +1716,7 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
var descriptors = element.TagHelperInfo.BindingResult.Descriptors;
|
var descriptors = element.TagHelperInfo.BindingResult.Descriptors;
|
||||||
var attributeName = node.Name.GetContent();
|
var attributeName = node.Name.GetContent();
|
||||||
var attributeValueNode = node.Value;
|
var attributeValueNode = node.Value;
|
||||||
|
|
||||||
var associatedDescriptors = descriptors.Where(descriptor =>
|
var associatedDescriptors = descriptors.Where(descriptor =>
|
||||||
descriptor.BoundAttributes.Any(attributeDescriptor => TagHelperMatchingConventions.CanSatisfyBoundAttribute(attributeName, attributeDescriptor)));
|
descriptor.BoundAttributes.Any(attributeDescriptor => TagHelperMatchingConventions.CanSatisfyBoundAttribute(attributeName, attributeDescriptor)));
|
||||||
|
|
||||||
|
|
@ -1723,24 +1724,47 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
{
|
{
|
||||||
foreach (var associatedDescriptor in associatedDescriptors)
|
foreach (var associatedDescriptor in associatedDescriptors)
|
||||||
{
|
{
|
||||||
var associatedAttributeDescriptor = associatedDescriptor.BoundAttributes.First(a =>
|
if (TagHelperMatchingConventions.TryGetFirstBoundAttributeMatch(
|
||||||
|
attributeName,
|
||||||
|
associatedDescriptor,
|
||||||
|
out var associatedAttributeDescriptor,
|
||||||
|
out var indexerMatch,
|
||||||
|
out var parameterMatch,
|
||||||
|
out var associatedAttributeParameterDescriptor))
|
||||||
{
|
{
|
||||||
return TagHelperMatchingConventions.CanSatisfyBoundAttribute(attributeName, a);
|
IntermediateNode attributeNode;
|
||||||
});
|
if (parameterMatch &&
|
||||||
|
TagHelperMatchingConventions.TryGetBoundAttributeParameter(attributeName, out var attributeNameWithoutParameter, out var _))
|
||||||
|
{
|
||||||
|
attributeNode = new TagHelperAttributeParameterIntermediateNode()
|
||||||
|
{
|
||||||
|
AttributeName = attributeName,
|
||||||
|
AttributeNameWithoutParameter = attributeNameWithoutParameter,
|
||||||
|
BoundAttributeParameter = associatedAttributeParameterDescriptor,
|
||||||
|
BoundAttribute = associatedAttributeDescriptor,
|
||||||
|
TagHelper = associatedDescriptor,
|
||||||
|
IsIndexerNameMatch = indexerMatch,
|
||||||
|
AttributeStructure = node.TagHelperAttributeInfo.AttributeStructure,
|
||||||
|
Source = BuildSourceSpanFromNode(attributeValueNode),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
attributeNode = new TagHelperPropertyIntermediateNode()
|
||||||
|
{
|
||||||
|
AttributeName = attributeName,
|
||||||
|
BoundAttribute = associatedAttributeDescriptor,
|
||||||
|
TagHelper = associatedDescriptor,
|
||||||
|
AttributeStructure = node.TagHelperAttributeInfo.AttributeStructure,
|
||||||
|
Source = BuildSourceSpanFromNode(attributeValueNode),
|
||||||
|
IsIndexerNameMatch = indexerMatch,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
var setTagHelperProperty = new TagHelperPropertyIntermediateNode()
|
_builder.Push(attributeNode);
|
||||||
{
|
VisitAttributeValue(attributeValueNode);
|
||||||
AttributeName = attributeName,
|
_builder.Pop();
|
||||||
BoundAttribute = associatedAttributeDescriptor,
|
}
|
||||||
TagHelper = associatedDescriptor,
|
|
||||||
AttributeStructure = node.TagHelperAttributeInfo.AttributeStructure,
|
|
||||||
Source = BuildSourceSpanFromNode(attributeValueNode),
|
|
||||||
IsIndexerNameMatch = TagHelperMatchingConventions.SatisfiesBoundAttributeIndexer(attributeName, associatedAttributeDescriptor),
|
|
||||||
};
|
|
||||||
|
|
||||||
_builder.Push(setTagHelperProperty);
|
|
||||||
VisitAttributeValue(attributeValueNode);
|
|
||||||
_builder.Pop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Intermediate
|
||||||
VisitDefault(node);
|
VisitDefault(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual void VisitTagHelperAttributeParameter(TagHelperAttributeParameterIntermediateNode node)
|
||||||
|
{
|
||||||
|
VisitDefault(node);
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void VisitComponent(ComponentIntermediateNode node)
|
public virtual void VisitComponent(ComponentIntermediateNode node)
|
||||||
{
|
{
|
||||||
VisitDefault(node);
|
VisitDefault(node);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
// 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 TagHelperAttributeParameterIntermediateNode : IntermediateNode
|
||||||
|
{
|
||||||
|
public override IntermediateNodeCollection Children { get; } = new IntermediateNodeCollection();
|
||||||
|
|
||||||
|
public string AttributeName { get; set; }
|
||||||
|
|
||||||
|
public string AttributeNameWithoutParameter { get; set; }
|
||||||
|
|
||||||
|
public AttributeStructure AttributeStructure { get; set; }
|
||||||
|
|
||||||
|
public BoundAttributeParameterDescriptor BoundAttributeParameter { 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.VisitTagHelperAttributeParameter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void FormatNode(IntermediateNodeFormatter formatter)
|
||||||
|
{
|
||||||
|
formatter.WriteContent(AttributeName);
|
||||||
|
|
||||||
|
formatter.WriteProperty(nameof(AttributeName), AttributeName);
|
||||||
|
formatter.WriteProperty(nameof(AttributeStructure), AttributeStructure.ToString());
|
||||||
|
formatter.WriteProperty(nameof(BoundAttribute), BoundAttribute?.DisplayName);
|
||||||
|
formatter.WriteProperty(nameof(BoundAttributeParameter), BoundAttributeParameter?.DisplayName);
|
||||||
|
formatter.WriteProperty(nameof(TagHelper), TagHelper?.DisplayName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -273,17 +273,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
||||||
// Determines the full name of the Type of the property corresponding to an attribute with the given name.
|
// Determines the full name of the Type of the property corresponding to an attribute with the given name.
|
||||||
private static string GetPropertyType(string name, IEnumerable<TagHelperDescriptor> descriptors)
|
private static string GetPropertyType(string name, IEnumerable<TagHelperDescriptor> descriptors)
|
||||||
{
|
{
|
||||||
var firstBoundAttribute = FindFirstBoundAttribute(name, descriptors);
|
foreach (var descriptor in descriptors)
|
||||||
var isBoundToIndexer = TagHelperMatchingConventions.SatisfiesBoundAttributeIndexer(name, firstBoundAttribute);
|
{
|
||||||
|
if (TagHelperMatchingConventions.TryGetFirstBoundAttributeMatch(name, descriptor, out var firstBoundAttribute, out var indexerMatch, out var _, out var _))
|
||||||
|
{
|
||||||
|
if (indexerMatch)
|
||||||
|
{
|
||||||
|
return firstBoundAttribute.IndexerTypeName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return firstBoundAttribute.TypeName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isBoundToIndexer)
|
return null;
|
||||||
{
|
|
||||||
return firstBoundAttribute?.IndexerTypeName;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return firstBoundAttribute?.TypeName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a TryParseResult for given name, filling in binding details.
|
// Create a TryParseResult for given name, filling in binding details.
|
||||||
|
|
@ -292,13 +297,39 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
||||||
IEnumerable<TagHelperDescriptor> descriptors,
|
IEnumerable<TagHelperDescriptor> descriptors,
|
||||||
HashSet<string> processedBoundAttributeNames)
|
HashSet<string> processedBoundAttributeNames)
|
||||||
{
|
{
|
||||||
var firstBoundAttribute = FindFirstBoundAttribute(name, descriptors);
|
var isBoundAttribute = false;
|
||||||
var isBoundAttribute = firstBoundAttribute != null;
|
var isBoundNonStringAttribute = false;
|
||||||
var isBoundNonStringAttribute = isBoundAttribute && !firstBoundAttribute.ExpectsStringValue(name);
|
var isBoundBooleanAttribute = false;
|
||||||
var isBoundBooleanAttribute = isBoundAttribute && firstBoundAttribute.ExpectsBooleanValue(name);
|
var isMissingDictionaryKey = false;
|
||||||
var isMissingDictionaryKey = isBoundAttribute &&
|
|
||||||
firstBoundAttribute.IndexerNamePrefix != null &&
|
foreach (var descriptor in descriptors)
|
||||||
name.Length == firstBoundAttribute.IndexerNamePrefix.Length;
|
{
|
||||||
|
if (TagHelperMatchingConventions.TryGetFirstBoundAttributeMatch(
|
||||||
|
name,
|
||||||
|
descriptor,
|
||||||
|
out var firstBoundAttribute,
|
||||||
|
out var indexerMatch,
|
||||||
|
out var parameterMatch,
|
||||||
|
out var boundAttributeParameter))
|
||||||
|
{
|
||||||
|
isBoundAttribute = true;
|
||||||
|
if (parameterMatch)
|
||||||
|
{
|
||||||
|
isBoundNonStringAttribute = !boundAttributeParameter.IsStringProperty;
|
||||||
|
isBoundBooleanAttribute = boundAttributeParameter.IsBooleanProperty;
|
||||||
|
isMissingDictionaryKey = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
isBoundNonStringAttribute = !firstBoundAttribute.ExpectsStringValue(name);
|
||||||
|
isBoundBooleanAttribute = firstBoundAttribute.ExpectsBooleanValue(name);
|
||||||
|
isMissingDictionaryKey = firstBoundAttribute.IndexerNamePrefix != null &&
|
||||||
|
name.Length == firstBoundAttribute.IndexerNamePrefix.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var isDuplicateAttribute = false;
|
var isDuplicateAttribute = false;
|
||||||
if (isBoundAttribute && !processedBoundAttributeNames.Add(name))
|
if (isBoundAttribute && !processedBoundAttributeNames.Add(name))
|
||||||
|
|
@ -318,18 +349,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finds first TagHelperAttributeDescriptor matching given name.
|
|
||||||
private static BoundAttributeDescriptor FindFirstBoundAttribute(
|
|
||||||
string name,
|
|
||||||
IEnumerable<TagHelperDescriptor> descriptors)
|
|
||||||
{
|
|
||||||
var firstBoundAttribute = descriptors
|
|
||||||
.SelectMany(descriptor => descriptor.BoundAttributes)
|
|
||||||
.FirstOrDefault(attributeDescriptor => TagHelperMatchingConventions.CanSatisfyBoundAttribute(name, attributeDescriptor));
|
|
||||||
|
|
||||||
return firstBoundAttribute;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetAttributeValueContent(RazorSyntaxNode attributeBlock)
|
private static string GetAttributeValueContent(RazorSyntaxNode attributeBlock)
|
||||||
{
|
{
|
||||||
if (attributeBlock is MarkupTagHelperAttributeSyntax tagHelperAttribute)
|
if (attributeBlock is MarkupTagHelperAttributeSyntax tagHelperAttribute)
|
||||||
|
|
|
||||||
|
|
@ -779,6 +779,41 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
return diagnostic;
|
return diagnostic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidBoundAttributeParameterNullOrWhitespace =
|
||||||
|
new RazorDiagnosticDescriptor(
|
||||||
|
$"{DiagnosticPrefix}3013",
|
||||||
|
() => Resources.TagHelper_InvalidBoundAttributeParameterNullOrWhitespace,
|
||||||
|
RazorDiagnosticSeverity.Error);
|
||||||
|
public static RazorDiagnostic CreateTagHelper_InvalidBoundAttributeParameterNullOrWhitespace(string attributeName)
|
||||||
|
{
|
||||||
|
var diagnostic = RazorDiagnostic.Create(
|
||||||
|
TagHelper_InvalidBoundAttributeParameterNullOrWhitespace,
|
||||||
|
new SourceSpan(SourceLocation.Undefined, contentLength: 0),
|
||||||
|
attributeName);
|
||||||
|
|
||||||
|
return diagnostic;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidBoundAttributeParameterName =
|
||||||
|
new RazorDiagnosticDescriptor(
|
||||||
|
$"{DiagnosticPrefix}3014",
|
||||||
|
() => Resources.TagHelper_InvalidBoundAttributeParameterName,
|
||||||
|
RazorDiagnosticSeverity.Error);
|
||||||
|
public static RazorDiagnostic CreateTagHelper_InvalidBoundAttributeParameterName(
|
||||||
|
string attributeName,
|
||||||
|
string invalidName,
|
||||||
|
char invalidCharacter)
|
||||||
|
{
|
||||||
|
var diagnostic = RazorDiagnostic.Create(
|
||||||
|
TagHelper_InvalidBoundAttributeParameterName,
|
||||||
|
new SourceSpan(SourceLocation.Undefined, contentLength: 0),
|
||||||
|
attributeName,
|
||||||
|
invalidName,
|
||||||
|
invalidCharacter);
|
||||||
|
|
||||||
|
return diagnostic;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Rewriter Errors
|
#region Rewriter Errors
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
public enum RazorDiagnosticSeverity
|
public enum RazorDiagnosticSeverity
|
||||||
{
|
{
|
||||||
// Purposely using the same value as Roslyn here.
|
// Purposely using the same value as Roslyn here.
|
||||||
|
Warning = 2,
|
||||||
Error = 3,
|
Error = 3,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -541,4 +541,10 @@
|
||||||
<data name="NamespaceDirective_NamespaceToken_Name" xml:space="preserve">
|
<data name="NamespaceDirective_NamespaceToken_Name" xml:space="preserve">
|
||||||
<value>Namespace</value>
|
<value>Namespace</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TagHelper_InvalidBoundAttributeParameterName" xml:space="preserve">
|
||||||
|
<value>Invalid tag helper bound attribute parameter '{1}' on bound attribute '{0}'. Tag helpers cannot bind to HTML attribute parameters with name '{1}' because the name contains a '{3}' character.</value>
|
||||||
|
</data>
|
||||||
|
<data name="TagHelper_InvalidBoundAttributeParameterNullOrWhitespace" xml:space="preserve">
|
||||||
|
<value>Invalid tag helper bound attribute parameter '{0}'. Tag helpers cannot bind to HTML attribute parameters with a null or empty name.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -128,7 +128,9 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
|
|
||||||
public static bool CanSatisfyBoundAttribute(string name, BoundAttributeDescriptor descriptor)
|
public static bool CanSatisfyBoundAttribute(string name, BoundAttributeDescriptor descriptor)
|
||||||
{
|
{
|
||||||
return SatisfiesBoundAttributeName(name, descriptor) || SatisfiesBoundAttributeIndexer(name, descriptor);
|
return SatisfiesBoundAttributeName(name, descriptor) ||
|
||||||
|
SatisfiesBoundAttributeIndexer(name, descriptor) ||
|
||||||
|
descriptor.BoundAttributeParameters.Any(p => SatisfiesBoundAttributeWithParameter(name, descriptor, p));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool SatisfiesBoundAttributeIndexer(string name, BoundAttributeDescriptor descriptor)
|
public static bool SatisfiesBoundAttributeIndexer(string name, BoundAttributeDescriptor descriptor)
|
||||||
|
|
@ -138,6 +140,84 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
name.StartsWith(descriptor.IndexerNamePrefix, StringComparison.OrdinalIgnoreCase);
|
name.StartsWith(descriptor.IndexerNamePrefix, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool SatisfiesBoundAttributeWithParameter(string name, BoundAttributeDescriptor parent, BoundAttributeParameterDescriptor descriptor)
|
||||||
|
{
|
||||||
|
if (TryGetBoundAttributeParameter(name, out var attributeName, out var parameterName))
|
||||||
|
{
|
||||||
|
var satisfiesBoundAttributeName = SatisfiesBoundAttributeName(attributeName, parent);
|
||||||
|
var satisfiesBoundAttributeIndexer = SatisfiesBoundAttributeIndexer(attributeName, parent);
|
||||||
|
var matchesParameter = string.Equals(descriptor.Name, parameterName, StringComparison.Ordinal);
|
||||||
|
return (satisfiesBoundAttributeName || satisfiesBoundAttributeIndexer) && matchesParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryGetBoundAttributeParameter(string fullAttributeName, out string boundAttributeName, out string parameterName)
|
||||||
|
{
|
||||||
|
boundAttributeName = null;
|
||||||
|
parameterName = null;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(fullAttributeName) && fullAttributeName.IndexOf(':') != -1)
|
||||||
|
{
|
||||||
|
var segments = fullAttributeName.Split(new[] { ':' }, 2);
|
||||||
|
boundAttributeName = segments[0];
|
||||||
|
parameterName = segments[1];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryGetFirstBoundAttributeMatch(
|
||||||
|
string name,
|
||||||
|
TagHelperDescriptor descriptor,
|
||||||
|
out BoundAttributeDescriptor boundAttribute,
|
||||||
|
out bool indexerMatch,
|
||||||
|
out bool parameterMatch,
|
||||||
|
out BoundAttributeParameterDescriptor boundAttributeParameter)
|
||||||
|
{
|
||||||
|
indexerMatch = false;
|
||||||
|
parameterMatch = false;
|
||||||
|
boundAttribute = null;
|
||||||
|
boundAttributeParameter = null;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(name) || descriptor == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First, check if we have a bound attribute descriptor that matches the parameter if it exists.
|
||||||
|
foreach (var attribute in descriptor.BoundAttributes)
|
||||||
|
{
|
||||||
|
boundAttributeParameter = attribute.BoundAttributeParameters.FirstOrDefault(
|
||||||
|
p => SatisfiesBoundAttributeWithParameter(name, attribute, p));
|
||||||
|
|
||||||
|
if (boundAttributeParameter != null)
|
||||||
|
{
|
||||||
|
boundAttribute = attribute;
|
||||||
|
indexerMatch = SatisfiesBoundAttributeIndexer(name, attribute);
|
||||||
|
parameterMatch = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we reach here, either the attribute name doesn't contain a parameter portion or
|
||||||
|
// the specified parameter isn't supported by any of the BoundAttributeDescriptors.
|
||||||
|
foreach (var attribute in descriptor.BoundAttributes)
|
||||||
|
{
|
||||||
|
if (CanSatisfyBoundAttribute(name, attribute))
|
||||||
|
{
|
||||||
|
boundAttribute = attribute;
|
||||||
|
indexerMatch = SatisfiesBoundAttributeIndexer(name, attribute);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No matches found.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private static bool SatisfiesBoundAttributeName(string name, BoundAttributeDescriptor descriptor)
|
private static bool SatisfiesBoundAttributeName(string name, BoundAttributeDescriptor descriptor)
|
||||||
{
|
{
|
||||||
return string.Equals(descriptor.Name, name, StringComparison.OrdinalIgnoreCase);
|
return string.Equals(descriptor.Name, name, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
|
||||||
|
|
@ -644,7 +644,7 @@ namespace Test
|
||||||
}"));
|
}"));
|
||||||
// Act
|
// Act
|
||||||
var generated = CompileToCSharp(@"
|
var generated = CompileToCSharp(@"
|
||||||
<MyComponent bind-Value-OnChanged=""ParentValue"" />
|
<MyComponent bind-Value=""ParentValue"" bind-Value:event=""OnChanged"" />
|
||||||
@code {
|
@code {
|
||||||
public int ParentValue { get; set; } = 42;
|
public int ParentValue { get; set; } = 42;
|
||||||
}");
|
}");
|
||||||
|
|
@ -674,7 +674,7 @@ namespace Test
|
||||||
}"));
|
}"));
|
||||||
|
|
||||||
var generated = CompileToCSharp(@"
|
var generated = CompileToCSharp(@"
|
||||||
<MyComponent bind-Value-OnChanged=""ParentValue"" />
|
<MyComponent bind-Value=""ParentValue"" bind-Value:event=""OnChanged"" />
|
||||||
@code {
|
@code {
|
||||||
public int ParentValue { get; set; } = 42;
|
public int ParentValue { get; set; } = 42;
|
||||||
}");
|
}");
|
||||||
|
|
@ -982,7 +982,7 @@ namespace Test
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var generated = CompileToCSharp(@"
|
var generated = CompileToCSharp(@"
|
||||||
<input type=""text"" bind=""@CurrentDate"" format-value=""MM/dd/yyyy""/>
|
<input type=""text"" bind=""@CurrentDate"" bind:format=""MM/dd/yyyy""/>
|
||||||
@code {
|
@code {
|
||||||
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
||||||
}");
|
}");
|
||||||
|
|
@ -1000,7 +1000,7 @@ namespace Test
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var generated = CompileToCSharp(@"
|
var generated = CompileToCSharp(@"
|
||||||
<input type=""text"" bind=""@CurrentDate"" format-value=""@Format""/>
|
<input type=""text"" bind=""@CurrentDate"" bind:format=""@Format""/>
|
||||||
@code {
|
@code {
|
||||||
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
||||||
|
|
||||||
|
|
@ -1056,7 +1056,7 @@ namespace Test
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var generated = CompileToCSharp(@"
|
var generated = CompileToCSharp(@"
|
||||||
<input type=""text"" bind-value-onchange=""@ParentValue"" />
|
<input type=""text"" bind-value=""@ParentValue"" bind-value:event=""onchange"" />
|
||||||
@code {
|
@code {
|
||||||
public int ParentValue { get; set; } = 42;
|
public int ParentValue { get; set; } = 42;
|
||||||
}");
|
}");
|
||||||
|
|
@ -1074,7 +1074,7 @@ namespace Test
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var generated = CompileToCSharp(@"
|
var generated = CompileToCSharp(@"
|
||||||
<input type=""text"" bind-value-onchange=""@CurrentDate"" format-value=""MM/dd"" />
|
<input type=""text"" bind-value=""@CurrentDate"" bind-value:event=""onchange"" bind-value:format=""MM/dd"" />
|
||||||
@code {
|
@code {
|
||||||
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
||||||
}");
|
}");
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ namespace Test
|
||||||
__o = Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck<System.Int32>(Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
__o = Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck<System.Int32>(Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
||||||
#nullable restore
|
#nullable restore
|
||||||
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
||||||
ParentValue
|
ParentValue
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
|
|
|
||||||
|
|
@ -14,16 +14,16 @@ Document -
|
||||||
CSharpCode -
|
CSharpCode -
|
||||||
IntermediateToken - - CSharp - #pragma warning restore 0414
|
IntermediateToken - - CSharp - #pragma warning restore 0414
|
||||||
MethodDeclaration - - protected override - void - BuildRenderTree
|
MethodDeclaration - - protected override - void - BuildRenderTree
|
||||||
Component - (0:0,0 [50] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent
|
Component - (0:0,0 [69] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent
|
||||||
ComponentAttribute - (35:0,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - AttributeStructure.DoubleQuotes
|
ComponentAttribute - (25:0,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - AttributeStructure.DoubleQuotes
|
||||||
CSharpExpression -
|
CSharpExpression -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
||||||
IntermediateToken - (35:0,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
|
IntermediateToken - (25:0,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
|
||||||
IntermediateToken - - CSharp - )
|
IntermediateToken - - CSharp - )
|
||||||
ComponentAttribute - (35:0,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - OnChanged - AttributeStructure.DoubleQuotes
|
ComponentAttribute - (25:0,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - OnChanged - AttributeStructure.DoubleQuotes
|
||||||
CSharpExpression -
|
CSharpExpression -
|
||||||
IntermediateToken - - CSharp - __value => ParentValue = __value
|
IntermediateToken - - CSharp - __value => ParentValue = __value
|
||||||
HtmlContent - (50:0,50 [2] x:\dir\subdir\Test\TestComponent.cshtml)
|
HtmlContent - (69:0,69 [2] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
IntermediateToken - (50:0,50 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
|
IntermediateToken - (69:0,69 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
|
||||||
CSharpCode - (59:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
CSharpCode - (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
IntermediateToken - (59:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n
|
IntermediateToken - (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
Source Location: (35:0,35 [11] x:\dir\subdir\Test\TestComponent.cshtml)
|
Source Location: (25:0,25 [11] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
|ParentValue|
|
|ParentValue|
|
||||||
Generated Location: (1022:25,35 [11] )
|
Generated Location: (1012:25,25 [11] )
|
||||||
|ParentValue|
|
|ParentValue|
|
||||||
|
|
||||||
Source Location: (59:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
Source Location: (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
|
|
|
|
||||||
public int ParentValue { get; set; } = 42;
|
public int ParentValue { get; set; } = 42;
|
||||||
|
|
|
|
||||||
Generated Location: (1627:47,7 [50] )
|
Generated Location: (1617:47,7 [50] )
|
||||||
|
|
|
|
||||||
public int ParentValue { get; set; } = 42;
|
public int ParentValue { get; set; } = 42;
|
||||||
|
|
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ namespace Test
|
||||||
__o = Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
__o = Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
||||||
#nullable restore
|
#nullable restore
|
||||||
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
||||||
ParentValue
|
ParentValue
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
|
|
|
||||||
|
|
@ -14,16 +14,16 @@ Document -
|
||||||
CSharpCode -
|
CSharpCode -
|
||||||
IntermediateToken - - CSharp - #pragma warning restore 0414
|
IntermediateToken - - CSharp - #pragma warning restore 0414
|
||||||
MethodDeclaration - - protected override - void - BuildRenderTree
|
MethodDeclaration - - protected override - void - BuildRenderTree
|
||||||
Component - (0:0,0 [50] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent
|
Component - (0:0,0 [69] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent
|
||||||
ComponentAttribute - (35:0,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - AttributeStructure.DoubleQuotes
|
ComponentAttribute - (25:0,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - AttributeStructure.DoubleQuotes
|
||||||
CSharpExpression -
|
CSharpExpression -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
||||||
IntermediateToken - (35:0,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
|
IntermediateToken - (25:0,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
|
||||||
IntermediateToken - - CSharp - )
|
IntermediateToken - - CSharp - )
|
||||||
ComponentAttribute - (35:0,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - OnChanged - AttributeStructure.DoubleQuotes
|
ComponentAttribute - (25:0,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - OnChanged - AttributeStructure.DoubleQuotes
|
||||||
CSharpExpression -
|
CSharpExpression -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => ParentValue = __value, ParentValue)
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => ParentValue = __value, ParentValue)
|
||||||
HtmlContent - (50:0,50 [2] x:\dir\subdir\Test\TestComponent.cshtml)
|
HtmlContent - (69:0,69 [2] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
IntermediateToken - (50:0,50 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
|
IntermediateToken - (69:0,69 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
|
||||||
CSharpCode - (59:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
CSharpCode - (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
IntermediateToken - (59:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n
|
IntermediateToken - (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
Source Location: (35:0,35 [11] x:\dir\subdir\Test\TestComponent.cshtml)
|
Source Location: (25:0,25 [11] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
|ParentValue|
|
|ParentValue|
|
||||||
Generated Location: (951:25,35 [11] )
|
Generated Location: (941:25,25 [11] )
|
||||||
|ParentValue|
|
|ParentValue|
|
||||||
|
|
||||||
Source Location: (59:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
Source Location: (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
|
|
|
|
||||||
public int ParentValue { get; set; } = 42;
|
public int ParentValue { get; set; } = 42;
|
||||||
|
|
|
|
||||||
Generated Location: (1595:46,7 [50] )
|
Generated Location: (1585:46,7 [50] )
|
||||||
|
|
|
|
||||||
public int ParentValue { get; set; } = 42;
|
public int ParentValue { get; set; } = 42;
|
||||||
|
|
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ namespace Test
|
||||||
__o = Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
__o = Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
||||||
#nullable restore
|
#nullable restore
|
||||||
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
||||||
CurrentDate
|
CurrentDate
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
|
|
|
||||||
|
|
@ -14,21 +14,21 @@ Document -
|
||||||
CSharpCode -
|
CSharpCode -
|
||||||
IntermediateToken - - CSharp - #pragma warning restore 0414
|
IntermediateToken - - CSharp - #pragma warning restore 0414
|
||||||
MethodDeclaration - - protected override - void - BuildRenderTree
|
MethodDeclaration - - protected override - void - BuildRenderTree
|
||||||
MarkupElement - (0:0,0 [77] x:\dir\subdir\Test\TestComponent.cshtml) - input
|
MarkupElement - (0:0,0 [101] x:\dir\subdir\Test\TestComponent.cshtml) - input
|
||||||
HtmlAttribute - - type=" - "
|
HtmlAttribute - - type=" - "
|
||||||
HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
|
HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
|
||||||
IntermediateToken - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
|
IntermediateToken - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
|
||||||
HtmlAttribute - (40:0,40 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
|
HtmlAttribute - (31:0,31 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
|
||||||
CSharpExpressionAttributeValue - -
|
CSharpExpressionAttributeValue - -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
||||||
IntermediateToken - (41:0,41 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
|
IntermediateToken - (32:0,32 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
|
||||||
IntermediateToken - - CSharp - ,
|
IntermediateToken - - CSharp - ,
|
||||||
IntermediateToken - - CSharp - "MM/dd"
|
IntermediateToken - - CSharp - "MM/dd"
|
||||||
IntermediateToken - - CSharp - )
|
IntermediateToken - - CSharp - )
|
||||||
HtmlAttribute - (40:0,40 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
|
HtmlAttribute - (31:0,31 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
|
||||||
CSharpExpressionAttributeValue - -
|
CSharpExpressionAttributeValue - -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => CurrentDate = __value, CurrentDate, "MM/dd")
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => CurrentDate = __value, CurrentDate, "MM/dd")
|
||||||
HtmlContent - (77:0,77 [2] x:\dir\subdir\Test\TestComponent.cshtml)
|
HtmlContent - (101:0,101 [2] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
IntermediateToken - (77:0,77 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
|
IntermediateToken - (101:0,101 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
|
||||||
CSharpCode - (86:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml)
|
CSharpCode - (110:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
IntermediateToken - (86:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n
|
IntermediateToken - (110:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
Source Location: (41:0,41 [11] x:\dir\subdir\Test\TestComponent.cshtml)
|
Source Location: (32:0,32 [11] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
|CurrentDate|
|
|CurrentDate|
|
||||||
Generated Location: (957:25,41 [11] )
|
Generated Location: (948:25,32 [11] )
|
||||||
|CurrentDate|
|
|CurrentDate|
|
||||||
|
|
||||||
Source Location: (86:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml)
|
Source Location: (110:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
|
|
|
|
||||||
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
||||||
|
|
|
|
||||||
Generated Location: (1320:36,7 [77] )
|
Generated Location: (1311:36,7 [77] )
|
||||||
|
|
|
|
||||||
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
||||||
|
|
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ namespace Test
|
||||||
__o = Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
__o = Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
||||||
#nullable restore
|
#nullable restore
|
||||||
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
||||||
ParentValue
|
ParentValue
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
|
|
|
||||||
|
|
@ -14,19 +14,19 @@ Document -
|
||||||
CSharpCode -
|
CSharpCode -
|
||||||
IntermediateToken - - CSharp - #pragma warning restore 0414
|
IntermediateToken - - CSharp - #pragma warning restore 0414
|
||||||
MethodDeclaration - - protected override - void - BuildRenderTree
|
MethodDeclaration - - protected override - void - BuildRenderTree
|
||||||
MarkupElement - (0:0,0 [56] x:\dir\subdir\Test\TestComponent.cshtml) - input
|
MarkupElement - (0:0,0 [75] x:\dir\subdir\Test\TestComponent.cshtml) - input
|
||||||
HtmlAttribute - - type=" - "
|
HtmlAttribute - - type=" - "
|
||||||
HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
|
HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
|
||||||
IntermediateToken - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
|
IntermediateToken - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
|
||||||
HtmlAttribute - (40:0,40 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
|
HtmlAttribute - (31:0,31 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
|
||||||
CSharpExpressionAttributeValue - -
|
CSharpExpressionAttributeValue - -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
||||||
IntermediateToken - (41:0,41 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
|
IntermediateToken - (32:0,32 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
|
||||||
IntermediateToken - - CSharp - )
|
IntermediateToken - - CSharp - )
|
||||||
HtmlAttribute - (40:0,40 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
|
HtmlAttribute - (31:0,31 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
|
||||||
CSharpExpressionAttributeValue - -
|
CSharpExpressionAttributeValue - -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => ParentValue = __value, ParentValue)
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => ParentValue = __value, ParentValue)
|
||||||
HtmlContent - (56:0,56 [2] x:\dir\subdir\Test\TestComponent.cshtml)
|
HtmlContent - (75:0,75 [2] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
IntermediateToken - (56:0,56 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
|
IntermediateToken - (75:0,75 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
|
||||||
CSharpCode - (65:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
CSharpCode - (84:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
IntermediateToken - (65:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n
|
IntermediateToken - (84:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
Source Location: (41:0,41 [11] x:\dir\subdir\Test\TestComponent.cshtml)
|
Source Location: (32:0,32 [11] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
|ParentValue|
|
|ParentValue|
|
||||||
Generated Location: (957:25,41 [11] )
|
Generated Location: (948:25,32 [11] )
|
||||||
|ParentValue|
|
|ParentValue|
|
||||||
|
|
||||||
Source Location: (65:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
Source Location: (84:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
|
|
|
|
||||||
public int ParentValue { get; set; } = 42;
|
public int ParentValue { get; set; } = 42;
|
||||||
|
|
|
|
||||||
Generated Location: (1302:36,7 [50] )
|
Generated Location: (1293:36,7 [50] )
|
||||||
|
|
|
|
||||||
public int ParentValue { get; set; } = 42;
|
public int ParentValue { get; set; } = 42;
|
||||||
|
|
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ namespace Test
|
||||||
,
|
,
|
||||||
#nullable restore
|
#nullable restore
|
||||||
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
||||||
Format
|
Format
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ Document -
|
||||||
CSharpCode -
|
CSharpCode -
|
||||||
IntermediateToken - - CSharp - #pragma warning restore 0414
|
IntermediateToken - - CSharp - #pragma warning restore 0414
|
||||||
MethodDeclaration - - protected override - void - BuildRenderTree
|
MethodDeclaration - - protected override - void - BuildRenderTree
|
||||||
MarkupElement - (0:0,0 [63] x:\dir\subdir\Test\TestComponent.cshtml) - input
|
MarkupElement - (0:0,0 [62] x:\dir\subdir\Test\TestComponent.cshtml) - input
|
||||||
HtmlAttribute - - type=" - "
|
HtmlAttribute - - type=" - "
|
||||||
HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
|
HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
|
||||||
IntermediateToken - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
|
IntermediateToken - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
|
||||||
|
|
@ -23,12 +23,12 @@ Document -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
||||||
IntermediateToken - (26:0,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
|
IntermediateToken - (26:0,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
|
||||||
IntermediateToken - - CSharp - ,
|
IntermediateToken - - CSharp - ,
|
||||||
IntermediateToken - (54:0,54 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Format
|
IntermediateToken - (53:0,53 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Format
|
||||||
IntermediateToken - - CSharp - )
|
IntermediateToken - - CSharp - )
|
||||||
HtmlAttribute - (25:0,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
|
HtmlAttribute - (25:0,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
|
||||||
CSharpExpressionAttributeValue - -
|
CSharpExpressionAttributeValue - -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => CurrentDate = __value, CurrentDate, Format)
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => CurrentDate = __value, CurrentDate, Format)
|
||||||
HtmlContent - (63:0,63 [2] x:\dir\subdir\Test\TestComponent.cshtml)
|
HtmlContent - (62:0,62 [2] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
IntermediateToken - (63:0,63 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
|
IntermediateToken - (62:0,62 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
|
||||||
CSharpCode - (72:1,7 [135] x:\dir\subdir\Test\TestComponent.cshtml)
|
CSharpCode - (71:1,7 [135] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
IntermediateToken - (72:1,7 [135] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n\n public string Format { get; set; } = "MM/dd/yyyy";\n
|
IntermediateToken - (71:1,7 [135] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n\n public string Format { get; set; } = "MM/dd/yyyy";\n
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,18 @@ Source Location: (26:0,26 [11] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
Generated Location: (942:25,26 [11] )
|
Generated Location: (942:25,26 [11] )
|
||||||
|CurrentDate|
|
|CurrentDate|
|
||||||
|
|
||||||
Source Location: (54:0,54 [6] x:\dir\subdir\Test\TestComponent.cshtml)
|
Source Location: (53:0,53 [6] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
|Format|
|
|Format|
|
||||||
Generated Location: (1145:33,54 [6] )
|
Generated Location: (1144:33,53 [6] )
|
||||||
|Format|
|
|Format|
|
||||||
|
|
||||||
Source Location: (72:1,7 [135] x:\dir\subdir\Test\TestComponent.cshtml)
|
Source Location: (71:1,7 [135] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
|
|
|
|
||||||
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
||||||
|
|
||||||
public string Format { get; set; } = "MM/dd/yyyy";
|
public string Format { get; set; } = "MM/dd/yyyy";
|
||||||
|
|
|
|
||||||
Generated Location: (1493:44,7 [135] )
|
Generated Location: (1492:44,7 [135] )
|
||||||
|
|
|
|
||||||
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ Document -
|
||||||
CSharpCode -
|
CSharpCode -
|
||||||
IntermediateToken - - CSharp - #pragma warning restore 0414
|
IntermediateToken - - CSharp - #pragma warning restore 0414
|
||||||
MethodDeclaration - - protected override - void - BuildRenderTree
|
MethodDeclaration - - protected override - void - BuildRenderTree
|
||||||
MarkupElement - (0:0,0 [66] x:\dir\subdir\Test\TestComponent.cshtml) - input
|
MarkupElement - (0:0,0 [65] x:\dir\subdir\Test\TestComponent.cshtml) - input
|
||||||
HtmlAttribute - - type=" - "
|
HtmlAttribute - - type=" - "
|
||||||
HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
|
HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
|
||||||
IntermediateToken - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
|
IntermediateToken - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
|
||||||
|
|
@ -28,7 +28,7 @@ Document -
|
||||||
HtmlAttribute - (25:0,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
|
HtmlAttribute - (25:0,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
|
||||||
CSharpExpressionAttributeValue - -
|
CSharpExpressionAttributeValue - -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => CurrentDate = __value, CurrentDate, "MM/dd/yyyy")
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => CurrentDate = __value, CurrentDate, "MM/dd/yyyy")
|
||||||
HtmlContent - (66:0,66 [2] x:\dir\subdir\Test\TestComponent.cshtml)
|
HtmlContent - (65:0,65 [2] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
IntermediateToken - (66:0,66 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
|
IntermediateToken - (65:0,65 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
|
||||||
CSharpCode - (75:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml)
|
CSharpCode - (74:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
IntermediateToken - (75:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n
|
IntermediateToken - (74:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ Source Location: (26:0,26 [11] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
Generated Location: (942:25,26 [11] )
|
Generated Location: (942:25,26 [11] )
|
||||||
|CurrentDate|
|
|CurrentDate|
|
||||||
|
|
||||||
Source Location: (75:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml)
|
Source Location: (74:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
|
|
|
|
||||||
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
||||||
|
|
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ namespace Test
|
||||||
builder.AddAttribute(1, "Value", Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck<System.Int32>(Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
builder.AddAttribute(1, "Value", Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck<System.Int32>(Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
||||||
#nullable restore
|
#nullable restore
|
||||||
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
||||||
ParentValue
|
ParentValue
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,14 @@ Document -
|
||||||
UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components
|
UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components
|
||||||
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
|
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
|
||||||
MethodDeclaration - - protected override - void - BuildRenderTree
|
MethodDeclaration - - protected override - void - BuildRenderTree
|
||||||
Component - (0:0,0 [50] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent
|
Component - (0:0,0 [69] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent
|
||||||
ComponentAttribute - (35:0,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - AttributeStructure.DoubleQuotes
|
ComponentAttribute - (25:0,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - AttributeStructure.DoubleQuotes
|
||||||
CSharpExpression -
|
CSharpExpression -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
||||||
IntermediateToken - (35:0,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
|
IntermediateToken - (25:0,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
|
||||||
IntermediateToken - - CSharp - )
|
IntermediateToken - - CSharp - )
|
||||||
ComponentAttribute - (35:0,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - OnChanged - AttributeStructure.DoubleQuotes
|
ComponentAttribute - (25:0,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - OnChanged - AttributeStructure.DoubleQuotes
|
||||||
CSharpExpression -
|
CSharpExpression -
|
||||||
IntermediateToken - - CSharp - __value => ParentValue = __value
|
IntermediateToken - - CSharp - __value => ParentValue = __value
|
||||||
CSharpCode - (59:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
CSharpCode - (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
IntermediateToken - (59:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n
|
IntermediateToken - (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
Source Location: (59:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
Source Location: (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
|
|
|
|
||||||
public int ParentValue { get; set; } = 42;
|
public int ParentValue { get; set; } = 42;
|
||||||
|
|
|
|
||||||
Generated Location: (1202:31,7 [50] )
|
Generated Location: (1192:31,7 [50] )
|
||||||
|
|
|
|
||||||
public int ParentValue { get; set; } = 42;
|
public int ParentValue { get; set; } = 42;
|
||||||
|
|
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ namespace Test
|
||||||
builder.AddAttribute(1, "Value", Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
builder.AddAttribute(1, "Value", Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
||||||
#nullable restore
|
#nullable restore
|
||||||
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
||||||
ParentValue
|
ParentValue
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,14 @@ Document -
|
||||||
UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components
|
UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components
|
||||||
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
|
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
|
||||||
MethodDeclaration - - protected override - void - BuildRenderTree
|
MethodDeclaration - - protected override - void - BuildRenderTree
|
||||||
Component - (0:0,0 [50] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent
|
Component - (0:0,0 [69] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent
|
||||||
ComponentAttribute - (35:0,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - AttributeStructure.DoubleQuotes
|
ComponentAttribute - (25:0,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - AttributeStructure.DoubleQuotes
|
||||||
CSharpExpression -
|
CSharpExpression -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
||||||
IntermediateToken - (35:0,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
|
IntermediateToken - (25:0,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
|
||||||
IntermediateToken - - CSharp - )
|
IntermediateToken - - CSharp - )
|
||||||
ComponentAttribute - (35:0,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - OnChanged - AttributeStructure.DoubleQuotes
|
ComponentAttribute - (25:0,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - OnChanged - AttributeStructure.DoubleQuotes
|
||||||
CSharpExpression -
|
CSharpExpression -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => ParentValue = __value, ParentValue)
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => ParentValue = __value, ParentValue)
|
||||||
CSharpCode - (59:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
CSharpCode - (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
IntermediateToken - (59:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n
|
IntermediateToken - (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
Source Location: (59:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
Source Location: (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
|
|
|
|
||||||
public int ParentValue { get; set; } = 42;
|
public int ParentValue { get; set; } = 42;
|
||||||
|
|
|
|
||||||
Generated Location: (1184:31,7 [50] )
|
Generated Location: (1174:31,7 [50] )
|
||||||
|
|
|
|
||||||
public int ParentValue { get; set; } = 42;
|
public int ParentValue { get; set; } = 42;
|
||||||
|
|
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Test
|
||||||
builder.AddAttribute(2, "value", Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
builder.AddAttribute(2, "value", Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
||||||
#nullable restore
|
#nullable restore
|
||||||
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
||||||
CurrentDate
|
CurrentDate
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
|
|
|
||||||
|
|
@ -7,19 +7,19 @@ Document -
|
||||||
UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components
|
UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components
|
||||||
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
|
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
|
||||||
MethodDeclaration - - protected override - void - BuildRenderTree
|
MethodDeclaration - - protected override - void - BuildRenderTree
|
||||||
MarkupElement - (0:0,0 [77] x:\dir\subdir\Test\TestComponent.cshtml) - input
|
MarkupElement - (0:0,0 [101] x:\dir\subdir\Test\TestComponent.cshtml) - input
|
||||||
HtmlAttribute - - type=" - "
|
HtmlAttribute - - type=" - "
|
||||||
HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
|
HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
|
||||||
IntermediateToken - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
|
IntermediateToken - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
|
||||||
HtmlAttribute - (40:0,40 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
|
HtmlAttribute - (31:0,31 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
|
||||||
CSharpExpressionAttributeValue - -
|
CSharpExpressionAttributeValue - -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
||||||
IntermediateToken - (41:0,41 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
|
IntermediateToken - (32:0,32 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
|
||||||
IntermediateToken - - CSharp - ,
|
IntermediateToken - - CSharp - ,
|
||||||
IntermediateToken - - CSharp - "MM/dd"
|
IntermediateToken - - CSharp - "MM/dd"
|
||||||
IntermediateToken - - CSharp - )
|
IntermediateToken - - CSharp - )
|
||||||
HtmlAttribute - (40:0,40 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
|
HtmlAttribute - (31:0,31 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
|
||||||
CSharpExpressionAttributeValue - -
|
CSharpExpressionAttributeValue - -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => CurrentDate = __value, CurrentDate, "MM/dd")
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => CurrentDate = __value, CurrentDate, "MM/dd")
|
||||||
CSharpCode - (86:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml)
|
CSharpCode - (110:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
IntermediateToken - (86:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n
|
IntermediateToken - (110:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
Source Location: (86:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml)
|
Source Location: (110:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
|
|
|
|
||||||
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
||||||
|
|
|
|
||||||
Generated Location: (1248:32,7 [77] )
|
Generated Location: (1239:32,7 [77] )
|
||||||
|
|
|
|
||||||
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
||||||
|
|
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Test
|
||||||
builder.AddAttribute(2, "value", Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
builder.AddAttribute(2, "value", Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
||||||
#nullable restore
|
#nullable restore
|
||||||
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
||||||
ParentValue
|
ParentValue
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
|
|
|
||||||
|
|
@ -7,17 +7,17 @@ Document -
|
||||||
UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components
|
UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components
|
||||||
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
|
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
|
||||||
MethodDeclaration - - protected override - void - BuildRenderTree
|
MethodDeclaration - - protected override - void - BuildRenderTree
|
||||||
MarkupElement - (0:0,0 [56] x:\dir\subdir\Test\TestComponent.cshtml) - input
|
MarkupElement - (0:0,0 [75] x:\dir\subdir\Test\TestComponent.cshtml) - input
|
||||||
HtmlAttribute - - type=" - "
|
HtmlAttribute - - type=" - "
|
||||||
HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
|
HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
|
||||||
IntermediateToken - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
|
IntermediateToken - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
|
||||||
HtmlAttribute - (40:0,40 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
|
HtmlAttribute - (31:0,31 [12] x:\dir\subdir\Test\TestComponent.cshtml) - value=" - "
|
||||||
CSharpExpressionAttributeValue - -
|
CSharpExpressionAttributeValue - -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
||||||
IntermediateToken - (41:0,41 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
|
IntermediateToken - (32:0,32 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ParentValue
|
||||||
IntermediateToken - - CSharp - )
|
IntermediateToken - - CSharp - )
|
||||||
HtmlAttribute - (40:0,40 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
|
HtmlAttribute - (31:0,31 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
|
||||||
CSharpExpressionAttributeValue - -
|
CSharpExpressionAttributeValue - -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => ParentValue = __value, ParentValue)
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => ParentValue = __value, ParentValue)
|
||||||
CSharpCode - (65:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
CSharpCode - (84:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
IntermediateToken - (65:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n
|
IntermediateToken - (84:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
Source Location: (65:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
Source Location: (84:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
|
|
|
|
||||||
public int ParentValue { get; set; } = 42;
|
public int ParentValue { get; set; } = 42;
|
||||||
|
|
|
|
||||||
Generated Location: (1230:32,7 [50] )
|
Generated Location: (1221:32,7 [50] )
|
||||||
|
|
|
|
||||||
public int ParentValue { get; set; } = 42;
|
public int ParentValue { get; set; } = 42;
|
||||||
|
|
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ namespace Test
|
||||||
,
|
,
|
||||||
#nullable restore
|
#nullable restore
|
||||||
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
|
||||||
Format
|
Format
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ Document -
|
||||||
UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components
|
UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components
|
||||||
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
|
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
|
||||||
MethodDeclaration - - protected override - void - BuildRenderTree
|
MethodDeclaration - - protected override - void - BuildRenderTree
|
||||||
MarkupElement - (0:0,0 [63] x:\dir\subdir\Test\TestComponent.cshtml) - input
|
MarkupElement - (0:0,0 [62] x:\dir\subdir\Test\TestComponent.cshtml) - input
|
||||||
HtmlAttribute - - type=" - "
|
HtmlAttribute - - type=" - "
|
||||||
HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
|
HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
|
||||||
IntermediateToken - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
|
IntermediateToken - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
|
||||||
|
|
@ -16,10 +16,10 @@ Document -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.BindMethods.GetValue(
|
||||||
IntermediateToken - (26:0,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
|
IntermediateToken - (26:0,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate
|
||||||
IntermediateToken - - CSharp - ,
|
IntermediateToken - - CSharp - ,
|
||||||
IntermediateToken - (54:0,54 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Format
|
IntermediateToken - (53:0,53 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Format
|
||||||
IntermediateToken - - CSharp - )
|
IntermediateToken - - CSharp - )
|
||||||
HtmlAttribute - (25:0,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
|
HtmlAttribute - (25:0,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
|
||||||
CSharpExpressionAttributeValue - -
|
CSharpExpressionAttributeValue - -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => CurrentDate = __value, CurrentDate, Format)
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => CurrentDate = __value, CurrentDate, Format)
|
||||||
CSharpCode - (72:1,7 [135] x:\dir\subdir\Test\TestComponent.cshtml)
|
CSharpCode - (71:1,7 [135] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
IntermediateToken - (72:1,7 [135] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n\n public string Format { get; set; } = "MM/dd/yyyy";\n
|
IntermediateToken - (71:1,7 [135] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n\n public string Format { get; set; } = "MM/dd/yyyy";\n
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
Source Location: (72:1,7 [135] x:\dir\subdir\Test\TestComponent.cshtml)
|
Source Location: (71:1,7 [135] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
|
|
|
|
||||||
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
||||||
|
|
||||||
public string Format { get; set; } = "MM/dd/yyyy";
|
public string Format { get; set; } = "MM/dd/yyyy";
|
||||||
|
|
|
|
||||||
Generated Location: (1421:40,7 [135] )
|
Generated Location: (1420:40,7 [135] )
|
||||||
|
|
|
|
||||||
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ Document -
|
||||||
UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components
|
UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components
|
||||||
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
|
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
|
||||||
MethodDeclaration - - protected override - void - BuildRenderTree
|
MethodDeclaration - - protected override - void - BuildRenderTree
|
||||||
MarkupElement - (0:0,0 [66] x:\dir\subdir\Test\TestComponent.cshtml) - input
|
MarkupElement - (0:0,0 [65] x:\dir\subdir\Test\TestComponent.cshtml) - input
|
||||||
HtmlAttribute - - type=" - "
|
HtmlAttribute - - type=" - "
|
||||||
HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
|
HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) -
|
||||||
IntermediateToken - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
|
IntermediateToken - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - text
|
||||||
|
|
@ -21,5 +21,5 @@ Document -
|
||||||
HtmlAttribute - (25:0,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
|
HtmlAttribute - (25:0,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - "
|
||||||
CSharpExpressionAttributeValue - -
|
CSharpExpressionAttributeValue - -
|
||||||
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => CurrentDate = __value, CurrentDate, "MM/dd/yyyy")
|
IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => CurrentDate = __value, CurrentDate, "MM/dd/yyyy")
|
||||||
CSharpCode - (75:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml)
|
CSharpCode - (74:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
IntermediateToken - (75:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n
|
IntermediateToken - (74:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
Source Location: (75:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml)
|
Source Location: (74:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml)
|
||||||
|
|
|
|
||||||
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);
|
||||||
|
|
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
//
|
//
|
||||||
// We handle a few different cases here:
|
// We handle a few different cases here:
|
||||||
//
|
//
|
||||||
// 1. When given an attribute like **anywhere**'bind-value-onchange="@FirstName"' we will
|
// 1. When given an attribute like **anywhere**'bind-value="@FirstName"' and 'bind-value:event="onchange"' we will
|
||||||
// generate the 'value' attribute and 'onchange' attribute.
|
// generate the 'value' attribute and 'onchange' attribute.
|
||||||
//
|
//
|
||||||
// We don't do any transformation or inference for this case, because the developer has
|
// We don't do any transformation or inference for this case, because the developer has
|
||||||
|
|
@ -143,15 +143,35 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
{
|
{
|
||||||
attribute.Documentation = ComponentResources.BindTagHelper_Fallback_Documentation;
|
attribute.Documentation = ComponentResources.BindTagHelper_Fallback_Documentation;
|
||||||
|
|
||||||
attribute.Name = "bind-...";
|
var attributeName = "bind-...";
|
||||||
|
attribute.Name = attributeName;
|
||||||
attribute.AsDictionary("bind-", typeof(object).FullName);
|
attribute.AsDictionary("bind-", typeof(object).FullName);
|
||||||
|
|
||||||
// WTE has a bug 15.7p1 where a Tag Helper without a display-name that looks like
|
// WTE has a bug 15.7p1 where a Tag Helper without a display-name that looks like
|
||||||
// a C# property will crash trying to create the toolips.
|
// a C# property will crash trying to create the toolips.
|
||||||
attribute.SetPropertyName("Bind");
|
attribute.SetPropertyName("Bind");
|
||||||
attribute.TypeName = "System.Collections.Generic.Dictionary<string, object>";
|
attribute.TypeName = "System.Collections.Generic.Dictionary<string, object>";
|
||||||
|
|
||||||
|
attribute.BindAttributeParameter(parameter =>
|
||||||
|
{
|
||||||
|
parameter.Name = "format";
|
||||||
|
parameter.TypeName = typeof(string).FullName;
|
||||||
|
parameter.Documentation = ComponentResources.BindTagHelper_Fallback_Format_Documentation;
|
||||||
|
|
||||||
|
parameter.SetPropertyName("Format");
|
||||||
|
});
|
||||||
|
|
||||||
|
attribute.BindAttributeParameter(parameter =>
|
||||||
|
{
|
||||||
|
parameter.Name = "event";
|
||||||
|
parameter.TypeName = typeof(string).FullName;
|
||||||
|
parameter.Documentation = string.Format(ComponentResources.BindTagHelper_Fallback_Event_Documentation, attributeName);
|
||||||
|
|
||||||
|
parameter.SetPropertyName("Event");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// This is no longer supported. This is just here so we can add a diagnostic later on when this matches.
|
||||||
builder.BindAttribute(attribute =>
|
builder.BindAttribute(attribute =>
|
||||||
{
|
{
|
||||||
attribute.Documentation = ComponentResources.BindTagHelper_Fallback_Format_Documentation;
|
attribute.Documentation = ComponentResources.BindTagHelper_Fallback_Format_Documentation;
|
||||||
|
|
@ -237,6 +257,7 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<TagHelperDescriptor> CreateElementBindTagHelpers(List<ElementBindData> data)
|
private List<TagHelperDescriptor> CreateElementBindTagHelpers(List<ElementBindData> data)
|
||||||
{
|
{
|
||||||
var results = new List<TagHelperDescriptor>();
|
var results = new List<TagHelperDescriptor>();
|
||||||
|
|
@ -251,6 +272,8 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
var formatName = entry.Suffix == null ? "Format_" + entry.ValueAttribute : "Format_" + entry.Suffix;
|
var formatName = entry.Suffix == null ? "Format_" + entry.ValueAttribute : "Format_" + entry.Suffix;
|
||||||
var formatAttributeName = entry.Suffix == null ? "format-" + entry.ValueAttribute : "format-" + entry.Suffix;
|
var formatAttributeName = entry.Suffix == null ? "format-" + entry.ValueAttribute : "format-" + entry.Suffix;
|
||||||
|
|
||||||
|
var eventName = entry.Suffix == null ? "Event_" + entry.ValueAttribute : "Event_" + entry.Suffix;
|
||||||
|
|
||||||
var builder = TagHelperDescriptorBuilder.Create(ComponentMetadata.Bind.TagHelperKind, name, ComponentsApi.AssemblyName);
|
var builder = TagHelperDescriptorBuilder.Create(ComponentMetadata.Bind.TagHelperKind, name, ComponentsApi.AssemblyName);
|
||||||
builder.Documentation = string.Format(
|
builder.Documentation = string.Format(
|
||||||
ComponentResources.BindTagHelper_Element_Documentation,
|
ComponentResources.BindTagHelper_Element_Documentation,
|
||||||
|
|
@ -315,14 +338,32 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
// WTE has a bug 15.7p1 where a Tag Helper without a display-name that looks like
|
// WTE has a bug 15.7p1 where a Tag Helper without a display-name that looks like
|
||||||
// a C# property will crash trying to create the toolips.
|
// a C# property will crash trying to create the toolips.
|
||||||
a.SetPropertyName(name);
|
a.SetPropertyName(name);
|
||||||
|
|
||||||
|
a.BindAttributeParameter(parameter =>
|
||||||
|
{
|
||||||
|
parameter.Name = "format";
|
||||||
|
parameter.TypeName = typeof(string).FullName;
|
||||||
|
parameter.Documentation = string.Format(ComponentResources.BindTagHelper_Element_Format_Documentation, attributeName);
|
||||||
|
|
||||||
|
parameter.SetPropertyName(formatName);
|
||||||
|
});
|
||||||
|
|
||||||
|
a.BindAttributeParameter(parameter =>
|
||||||
|
{
|
||||||
|
parameter.Name = "event";
|
||||||
|
parameter.TypeName = typeof(string).FullName;
|
||||||
|
parameter.Documentation = string.Format(ComponentResources.BindTagHelper_Element_Event_Documentation, attributeName);
|
||||||
|
|
||||||
|
parameter.SetPropertyName(eventName);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// This is no longer supported. This is just here so we can add a diagnostic later on when this matches.
|
||||||
builder.BindAttribute(attribute =>
|
builder.BindAttribute(attribute =>
|
||||||
{
|
{
|
||||||
attribute.Documentation = string.Format(ComponentResources.BindTagHelper_Element_Format_Documentation, attributeName);
|
|
||||||
|
|
||||||
attribute.Name = formatAttributeName;
|
attribute.Name = formatAttributeName;
|
||||||
attribute.TypeName = "System.String";
|
attribute.TypeName = "System.String";
|
||||||
|
attribute.Documentation = string.Format(ComponentResources.BindTagHelper_Element_Format_Documentation, attributeName);
|
||||||
|
|
||||||
// WTE has a bug 15.7p1 where a Tag Helper without a display-name that looks like
|
// WTE has a bug 15.7p1 where a Tag Helper without a display-name that looks like
|
||||||
// a C# property will crash trying to create the toolips.
|
// a C# property will crash trying to create the toolips.
|
||||||
|
|
@ -376,7 +417,6 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
if (tagHelper.BoundAttributes[j].Name == valueAttributeName)
|
if (tagHelper.BoundAttributes[j].Name == valueAttributeName)
|
||||||
{
|
{
|
||||||
valueAttribute = tagHelper.BoundAttributes[j];
|
valueAttribute = tagHelper.BoundAttributes[j];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tagHelper.BoundAttributes[j].Name == expressionAttributeName)
|
if (tagHelper.BoundAttributes[j].Name == expressionAttributeName)
|
||||||
|
|
|
||||||
|
|
@ -395,33 +395,28 @@ namespace Test
|
||||||
Assert.False(attribute.IsBooleanProperty);
|
Assert.False(attribute.IsBooleanProperty);
|
||||||
Assert.False(attribute.IsEnum);
|
Assert.False(attribute.IsEnum);
|
||||||
|
|
||||||
attribute = Assert.Single(bind.BoundAttributes, a => a.Name.StartsWith("format"));
|
var parameter = Assert.Single(attribute.BoundAttributeParameters, a => a.Name.Equals("format"));
|
||||||
|
|
||||||
// Invariants
|
// Invariants
|
||||||
Assert.Empty(attribute.Diagnostics);
|
Assert.Empty(parameter.Diagnostics);
|
||||||
Assert.False(attribute.HasErrors);
|
Assert.False(parameter.HasErrors);
|
||||||
Assert.Equal(ComponentMetadata.Bind.TagHelperKind, attribute.Kind);
|
Assert.Equal(ComponentMetadata.Bind.TagHelperKind, parameter.Kind);
|
||||||
Assert.False(attribute.IsDefaultKind());
|
Assert.False(parameter.IsDefaultKind());
|
||||||
Assert.False(attribute.HasIndexer);
|
|
||||||
Assert.Null(attribute.IndexerNamePrefix);
|
|
||||||
Assert.Null(attribute.IndexerTypeName);
|
|
||||||
Assert.False(attribute.IsIndexerBooleanProperty);
|
|
||||||
Assert.False(attribute.IsIndexerStringProperty);
|
|
||||||
|
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
"Specifies a format to convert the value specified by the 'bind' attribute. " +
|
"Specifies a format to convert the value specified by the 'bind' attribute. " +
|
||||||
"The format string can currently only be used with expressions of type <code>DateTime</code>.",
|
"The format string can currently only be used with expressions of type <code>DateTime</code>.",
|
||||||
attribute.Documentation);
|
parameter.Documentation);
|
||||||
|
|
||||||
Assert.Equal("format-myprop", attribute.Name);
|
Assert.Equal("format", parameter.Name);
|
||||||
Assert.Equal("Format_myprop", attribute.GetPropertyName());
|
Assert.Equal("Format_myprop", parameter.GetPropertyName());
|
||||||
Assert.Equal("string Test.BindAttributes.Format_myprop", attribute.DisplayName);
|
Assert.Equal(":format", parameter.DisplayName);
|
||||||
|
|
||||||
// Defined from the property type
|
// Defined from the property type
|
||||||
Assert.Equal("System.String", attribute.TypeName);
|
Assert.Equal("System.String", parameter.TypeName);
|
||||||
Assert.True(attribute.IsStringProperty);
|
Assert.True(parameter.IsStringProperty);
|
||||||
Assert.False(attribute.IsBooleanProperty);
|
Assert.False(parameter.IsBooleanProperty);
|
||||||
Assert.False(attribute.IsEnum);
|
Assert.False(parameter.IsEnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -529,10 +524,10 @@ namespace Test
|
||||||
Assert.Equal("Bind", attribute.GetPropertyName());
|
Assert.Equal("Bind", attribute.GetPropertyName());
|
||||||
Assert.Equal("object Test.BindAttributes.Bind", attribute.DisplayName);
|
Assert.Equal("object Test.BindAttributes.Bind", attribute.DisplayName);
|
||||||
|
|
||||||
attribute = Assert.Single(bind.BoundAttributes, a => a.Name.StartsWith("format"));
|
var parameter = Assert.Single(attribute.BoundAttributeParameters, a => a.Name.Equals("format"));
|
||||||
Assert.Equal("format-myprop", attribute.Name);
|
Assert.Equal("format", parameter.Name);
|
||||||
Assert.Equal("Format_myprop", attribute.GetPropertyName());
|
Assert.Equal("Format_myprop", parameter.GetPropertyName());
|
||||||
Assert.Equal("string Test.BindAttributes.Format_myprop", attribute.DisplayName);
|
Assert.Equal(":format", parameter.DisplayName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -597,10 +592,10 @@ namespace Test
|
||||||
Assert.Equal("Bind", attribute.GetPropertyName());
|
Assert.Equal("Bind", attribute.GetPropertyName());
|
||||||
Assert.Equal("object Test.BindAttributes.Bind", attribute.DisplayName);
|
Assert.Equal("object Test.BindAttributes.Bind", attribute.DisplayName);
|
||||||
|
|
||||||
attribute = Assert.Single(bind.BoundAttributes, a => a.Name.StartsWith("format"));
|
var parameter = Assert.Single(attribute.BoundAttributeParameters, a => a.Name.Equals("format"));
|
||||||
Assert.Equal("format-myprop", attribute.Name);
|
Assert.Equal("format", parameter.Name);
|
||||||
Assert.Equal("Format_myprop", attribute.GetPropertyName());
|
Assert.Equal("Format_myprop", parameter.GetPropertyName());
|
||||||
Assert.Equal("string Test.BindAttributes.Format_myprop", attribute.DisplayName);
|
Assert.Equal(":format", parameter.DisplayName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -665,10 +660,10 @@ namespace Test
|
||||||
Assert.Equal("Bind_somevalue", attribute.GetPropertyName());
|
Assert.Equal("Bind_somevalue", attribute.GetPropertyName());
|
||||||
Assert.Equal("object Test.BindAttributes.Bind_somevalue", attribute.DisplayName);
|
Assert.Equal("object Test.BindAttributes.Bind_somevalue", attribute.DisplayName);
|
||||||
|
|
||||||
attribute = Assert.Single(bind.BoundAttributes, a => a.Name.StartsWith("format"));
|
var parameter = Assert.Single(attribute.BoundAttributeParameters, a => a.Name.Equals("format"));
|
||||||
Assert.Equal("format-somevalue", attribute.Name);
|
Assert.Equal("format", parameter.Name);
|
||||||
Assert.Equal("Format_somevalue", attribute.GetPropertyName());
|
Assert.Equal("Format_somevalue", parameter.GetPropertyName());
|
||||||
Assert.Equal("string Test.BindAttributes.Format_somevalue", attribute.DisplayName);
|
Assert.Equal(":format", parameter.DisplayName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -710,7 +705,7 @@ namespace Test
|
||||||
|
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
"Binds the provided expression to an attribute and a change event, based on the naming of " +
|
"Binds the provided expression to an attribute and a change event, based on the naming of " +
|
||||||
"the bind attribute. For example: <code>bind-value-onchange=\"...\"</code> will assign the " +
|
"the bind attribute. For example: <code>bind-value=\"...\"</code> and <code>bind-value:event=\"onchange\"</code> will assign the " +
|
||||||
"current value of the expression to the 'value' attribute, and assign a delegate that attempts " +
|
"current value of the expression to the 'value' attribute, and assign a delegate that attempts " +
|
||||||
"to set the value to the 'onchange' attribute.",
|
"to set the value to the 'onchange' attribute.",
|
||||||
bind.Documentation);
|
bind.Documentation);
|
||||||
|
|
@ -753,7 +748,7 @@ namespace Test
|
||||||
|
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
"Binds the provided expression to an attribute and a change event, based on the naming of " +
|
"Binds the provided expression to an attribute and a change event, based on the naming of " +
|
||||||
"the bind attribute. For example: <code>bind-value-onchange=\"...\"</code> will assign the " +
|
"the bind attribute. For example: <code>bind-value=\"...\"</code> and <code>bind-value:event=\"onchange\"</code> will assign the " +
|
||||||
"current value of the expression to the 'value' attribute, and assign a delegate that attempts " +
|
"current value of the expression to the 'value' attribute, and assign a delegate that attempts " +
|
||||||
"to set the value to the 'onchange' attribute.",
|
"to set the value to the 'onchange' attribute.",
|
||||||
attribute.Documentation);
|
attribute.Documentation);
|
||||||
|
|
@ -770,37 +765,30 @@ namespace Test
|
||||||
Assert.False(attribute.IsBooleanProperty);
|
Assert.False(attribute.IsBooleanProperty);
|
||||||
Assert.False(attribute.IsEnum);
|
Assert.False(attribute.IsEnum);
|
||||||
|
|
||||||
attribute = Assert.Single(bind.BoundAttributes, a => a.Name.StartsWith("format"));
|
var parameter = Assert.Single(attribute.BoundAttributeParameters, a => a.Name.Equals("format"));
|
||||||
|
|
||||||
// Invariants
|
// Invariants
|
||||||
Assert.Empty(attribute.Diagnostics);
|
Assert.Empty(parameter.Diagnostics);
|
||||||
Assert.False(attribute.HasErrors);
|
Assert.False(parameter.HasErrors);
|
||||||
Assert.Equal(ComponentMetadata.Bind.TagHelperKind, attribute.Kind);
|
Assert.Equal(ComponentMetadata.Bind.TagHelperKind, parameter.Kind);
|
||||||
Assert.False(attribute.IsDefaultKind());
|
Assert.False(parameter.IsDefaultKind());
|
||||||
Assert.True(attribute.HasIndexer);
|
|
||||||
Assert.Equal("format-", attribute.IndexerNamePrefix);
|
|
||||||
Assert.Equal("System.String", attribute.IndexerTypeName);
|
|
||||||
Assert.False(attribute.IsIndexerBooleanProperty);
|
|
||||||
Assert.True(attribute.IsIndexerStringProperty);
|
|
||||||
|
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
"Specifies a format to convert the value specified by the corresponding bind attribute. " +
|
"Specifies a format to convert the value specified by the corresponding bind attribute. " +
|
||||||
"For example: <code>format-value=\"...\"</code> will apply a format string to the value " +
|
"For example: <code>bind-value:format=\"...\"</code> will apply a format string to the value " +
|
||||||
"specified in <code>bind-value-...</code>. The format string can currently only be used with " +
|
"specified in <code>bind-value=\"...\"</code>. The format string can currently only be used with " +
|
||||||
"expressions of type <code>DateTime</code>.",
|
"expressions of type <code>DateTime</code>.",
|
||||||
attribute.Documentation);
|
parameter.Documentation);
|
||||||
|
|
||||||
Assert.Equal("format-...", attribute.Name);
|
Assert.Equal("format", parameter.Name);
|
||||||
Assert.Equal("Format", attribute.GetPropertyName());
|
Assert.Equal("Format", parameter.GetPropertyName());
|
||||||
Assert.Equal(
|
Assert.Equal(":format", parameter.DisplayName);
|
||||||
"System.Collections.Generic.Dictionary<string, string> Microsoft.AspNetCore.Components.Bind.Format",
|
|
||||||
attribute.DisplayName);
|
|
||||||
|
|
||||||
// Defined from the property type
|
// Defined from the property type
|
||||||
Assert.Equal("System.Collections.Generic.Dictionary<string, string>", attribute.TypeName);
|
Assert.Equal("System.String", parameter.TypeName);
|
||||||
Assert.False(attribute.IsStringProperty);
|
Assert.True(parameter.IsStringProperty);
|
||||||
Assert.False(attribute.IsBooleanProperty);
|
Assert.False(parameter.IsBooleanProperty);
|
||||||
Assert.False(attribute.IsEnum);
|
Assert.False(parameter.IsEnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,11 @@ 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)
|
||||||
|
{
|
||||||
|
WriteContentNode(node, node.AttributeName, string.Format("HtmlAttributeValueStyle.{0}", node.AttributeStructure));
|
||||||
|
}
|
||||||
|
|
||||||
public override void VisitComponent(ComponentIntermediateNode node)
|
public override void VisitComponent(ComponentIntermediateNode node)
|
||||||
{
|
{
|
||||||
WriteContentNode(node, node.TagName);
|
WriteContentNode(node, node.TagName);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue