From 5bad5de7ee95848f3a39334649d3d68a2cca13b9 Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Tue, 21 May 2019 13:07:23 -0700 Subject: [PATCH] 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 https://github.com/dotnet/aspnetcore-tooling/commit/9bbf2409483856b9949d11212eae62729a3a9005 --- .../src/BoundAttributeDescriptor.cs | 2 + .../src/BoundAttributeDescriptorBuilder.cs | 7 + ...undAttributeDescriptorBuilderExtensions.cs | 34 +++- .../src/BoundAttributeDescriptorExtensions.cs | 22 +++ .../src/BoundAttributeParameterDescriptor.cs | 67 +++++++ ...oundAttributeParameterDescriptorBuilder.cs | 24 +++ ...undAttributeParameterDescriptorComparer.cs | 79 ++++++++ .../src/ComponentResources.resx | 10 +- .../Components/ComponentBindLoweringPass.cs | 178 +++++++++++++++--- .../Components/ComponentDiagnosticFactory.cs | 45 ++++- .../src/DefaultBoundAttributeDescriptor.cs | 2 + .../DefaultBoundAttributeDescriptorBuilder.cs | 37 ++++ ...efaultBoundAttributeParameterDescriptor.cs | 34 ++++ ...oundAttributeParameterDescriptorBuilder.cs | 106 +++++++++++ ...faultRazorIntermediateNodeLoweringPhase.cs | 56 ++++-- .../Intermediate/IntermediateNodeVisitor.cs | 5 + ...elperAttributeParameterIntermediateNode.cs | 47 +++++ .../src/Legacy/TagHelperBlockRewriter.cs | 77 +++++--- .../src/RazorDiagnosticFactory.cs | 35 ++++ .../src/RazorDiagnosticSeverity.cs | 1 + .../src/Resources.resx | 6 + .../src/TagHelperMatchingConventions.cs | 82 +++++++- .../ComponentCodeGenerationTestBase.cs | 12 +- .../TestComponent.codegen.cs | 2 +- .../TestComponent.ir.txt | 16 +- .../TestComponent.mappings.txt | 8 +- .../TestComponent.codegen.cs | 2 +- .../TestComponent.ir.txt | 16 +- .../TestComponent.mappings.txt | 8 +- .../TestComponent.codegen.cs | 2 +- .../TestComponent.ir.txt | 16 +- .../TestComponent.mappings.txt | 8 +- .../TestComponent.codegen.cs | 2 +- .../TestComponent.ir.txt | 16 +- .../TestComponent.mappings.txt | 8 +- .../TestComponent.codegen.cs | 2 +- .../TestComponent.ir.txt | 12 +- .../TestComponent.mappings.txt | 8 +- .../TestComponent.ir.txt | 10 +- .../TestComponent.mappings.txt | 2 +- .../TestComponent.codegen.cs | 2 +- .../TestComponent.ir.txt | 12 +- .../TestComponent.mappings.txt | 4 +- .../TestComponent.codegen.cs | 2 +- .../TestComponent.ir.txt | 12 +- .../TestComponent.mappings.txt | 4 +- .../TestComponent.codegen.cs | 2 +- .../TestComponent.ir.txt | 12 +- .../TestComponent.mappings.txt | 4 +- .../TestComponent.codegen.cs | 2 +- .../TestComponent.ir.txt | 12 +- .../TestComponent.mappings.txt | 4 +- .../TestComponent.codegen.cs | 2 +- .../TestComponent.ir.txt | 8 +- .../TestComponent.mappings.txt | 4 +- .../TestComponent.ir.txt | 6 +- .../TestComponent.mappings.txt | 2 +- .../src/BindTagHelperDescriptorProvider.cs | 50 ++++- .../BindTagHelperDescriptorProviderTest.cs | 96 +++++----- .../IntermediateNodeWriter.cs | 5 + 60 files changed, 1089 insertions(+), 262 deletions(-) create mode 100644 src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeParameterDescriptor.cs create mode 100644 src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeParameterDescriptorBuilder.cs create mode 100644 src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeParameterDescriptorComparer.cs create mode 100644 src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeParameterDescriptor.cs create mode 100644 src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeParameterDescriptorBuilder.cs create mode 100644 src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/TagHelperAttributeParameterIntermediateNode.cs diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeDescriptor.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeDescriptor.cs index b416fddd61..96a0119ad8 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeDescriptor.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeDescriptor.cs @@ -47,6 +47,8 @@ namespace Microsoft.AspNetCore.Razor.Language public IReadOnlyDictionary Metadata { get; protected set; } + public virtual IReadOnlyList BoundAttributeParameters { get; protected set; } + public bool HasErrors { get diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeDescriptorBuilder.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeDescriptorBuilder.cs index b2cbfba675..b6fb01d7ad 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeDescriptorBuilder.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeDescriptorBuilder.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Generic; namespace Microsoft.AspNetCore.Razor.Language @@ -26,5 +27,11 @@ namespace Microsoft.AspNetCore.Razor.Language public abstract IDictionary Metadata { get; } public abstract RazorDiagnosticCollection Diagnostics { get; } + + public virtual IReadOnlyList BoundAttributeParameters { get; } + + public virtual void BindAttributeParameter(Action configure) + { + } } } diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeDescriptorBuilderExtensions.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeDescriptorBuilderExtensions.cs index 8d1ab038ab..d253429102 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeDescriptorBuilderExtensions.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeDescriptorBuilderExtensions.cs @@ -29,9 +29,9 @@ namespace Microsoft.AspNetCore.Razor.Language 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; @@ -51,5 +51,35 @@ namespace Microsoft.AspNetCore.Razor.Language builder.IndexerAttributeNamePrefix = attributeNamePrefix; 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; + } } } diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeDescriptorExtensions.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeDescriptorExtensions.cs index 62b713a8fe..5b5fbbf1ea 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeDescriptorExtensions.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeDescriptorExtensions.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Linq; namespace Microsoft.AspNetCore.Razor.Language { @@ -49,5 +50,26 @@ namespace Microsoft.AspNetCore.Razor.Language var isIndexerNameMatch = TagHelperMatchingConventions.SatisfiesBoundAttributeIndexer(name, attribute); 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; + } } } \ No newline at end of file diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeParameterDescriptor.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeParameterDescriptor.cs new file mode 100644 index 0000000000..b0c98d8400 --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeParameterDescriptor.cs @@ -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 + { + 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 Diagnostics { get; protected set; } + + public IReadOnlyDictionary 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); + } + } +} diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeParameterDescriptorBuilder.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeParameterDescriptorBuilder.cs new file mode 100644 index 0000000000..64ab98a6ed --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeParameterDescriptorBuilder.cs @@ -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 Metadata { get; } + + public abstract RazorDiagnosticCollection Diagnostics { get; } + } +} diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeParameterDescriptorComparer.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeParameterDescriptorComparer.cs new file mode 100644 index 0000000000..4f183bee01 --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/BoundAttributeParameterDescriptorComparer.cs @@ -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 + { + /// + /// A default instance of the . + /// + public static readonly BoundAttributeParameterDescriptorComparer Default = new BoundAttributeParameterDescriptorComparer(); + + /// + /// A default instance of the that does case-sensitive comparison. + /// + 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; + } + } +} diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/ComponentResources.resx b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/ComponentResources.resx index 48b636ec27..7a28e7bc11 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/ComponentResources.resx +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/ComponentResources.resx @@ -123,14 +123,20 @@ Binds the provided expression to the '{0}' attribute and a change event delegate to the '{1}' attribute. + + Specifies the event handler name to attach for change notifications for the value provided by the '{0}' attribute. + 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>. - 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. + 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. + + + Specifies the event handler name to attach for change notifications for the value provided by the '{0}' 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 specified in <code>bind-value-...</code>. The format string can currently only be used with expressions of type <code>DateTime</code>. + 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>. Specifies the parameter name for the '{0}' child content expression. diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentBindLoweringPass.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentBindLoweringPass.cs index a02fd59235..6873560b1f 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentBindLoweringPass.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentBindLoweringPass.cs @@ -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. var references = documentNode.FindDescendantReferences(); + var parameterReferences = documentNode.FindDescendantReferences(); var parents = new HashSet(); for (var i = 0; i < references.Count; i++) { parents.Add(references[i].Parent); } + for (var i = 0; i < parameterReferences.Count; i++) + { + parents.Add(parameterReferences[i].Parent); + } foreach (var parent in parents) { ProcessDuplicates(parent); } + // First, collect all the non-parameterized bind or bind-* attributes. + var bindEntries = new Dictionary(); for (var i = 0; i < references.Count; i++) { var reference = references[i]; @@ -55,14 +62,60 @@ namespace Microsoft.AspNetCore.Razor.Language.Components if (node.TagHelper.IsBindTagHelper() && node.AttributeName.StartsWith("bind")) { - // Workaround for https://github.com/aspnet/Blazor/issues/703 - var rewritten = RewriteUsage(reference.Parent, node); - reference.Remove(); + bindEntries[node.AttributeName] = new BindEntry(reference); + } + } - 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 // 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 && - attribute.TagHelper != null && - attribute.TagHelper.IsFallbackBindTagHelper()) + tagHelper != null && + tagHelper.IsFallbackBindTagHelper()) { 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 && - duplicate.TagHelper != null && - duplicate.TagHelper.IsBindTagHelper() && - duplicate.AttributeName == attribute.AttributeName && + duplicateTagHelper != null && + duplicateTagHelper.IsBindTagHelper() && + duplicateAttributeName == attributeName && !object.ReferenceEquals(attribute, duplicate)) { // 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 // when a specific attribute is **not** present. if (attribute != null && - attribute.TagHelper != null && - attribute.TagHelper.IsInputElementFallbackBindTagHelper()) + tagHelper != null && + tagHelper.IsInputElementFallbackBindTagHelper()) { 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 && - duplicate.TagHelper != null && - duplicate.TagHelper.IsInputElementBindTagHelper() && - duplicate.AttributeName == attribute.AttributeName && + duplicateTagHelper != null && + duplicateTagHelper.IsInputElementBindTagHelper() && + duplicateAttributeName == attributeName && !object.ReferenceEquals(attribute, duplicate)) { // 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. // @@ -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 // 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 + var node = bindEntry.BindNode; if (!TryComputeAttributeNames( parent, - node, - node.AttributeName, + bindEntry, out var valueAttributeName, out var changeAttributeName, 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 // two nodes we generate. IntermediateToken format = null; + if (bindEntry.BindFormatNode != null) + { + format = GetAttributeContent(bindEntry.BindFormatNode); + } + if (TryGetFormatNode( parent, node, valueAttributeName, out var formatNode)) { - // Don't write the format out as its own attribute, just capture it as a string - // or expression. + // If there is a format- attribute present, add a warning to say that it's unsupported. parent.Children.Remove(formatNode); - format = GetAttributeContent(formatNode); + parent.Diagnostics.Add(ComponentDiagnosticFactory.CreateBindAttribute_FormatNode_Unsupported(formatNode.Source)); } var valueExpressionTokens = new List(); @@ -336,10 +429,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Components } private bool TryParseBindAttribute( - string attributeName, + BindEntry bindEntry, out string valueAttributeName, out string changeAttributeName) { + var attributeName = bindEntry.BindNode.AttributeName; valueAttributeName = null; changeAttributeName = null; @@ -348,6 +442,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Components return false; } + if (bindEntry.BindEventNode != null) + { + changeAttributeName = GetAttributeContent(bindEntry.BindEventNode)?.Content?.Trim('"'); + } + if (attributeName == "bind") { return true; @@ -369,8 +468,9 @@ namespace Microsoft.AspNetCore.Razor.Language.Components return true; case 3: - changeAttributeName = segments[2]; valueAttributeName = segments[1]; + changeAttributeName = segments[2]; + bindEntry.BindNode.Diagnostics.Add(ComponentDiagnosticFactory.CreateBindAttribute_UnsupportedFormat(bindEntry.BindNode.Source)); return true; 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'. private bool TryComputeAttributeNames( IntermediateNode parent, - TagHelperPropertyIntermediateNode node, - string attributeName, + BindEntry bindEntry, out string valueAttributeName, out string changeAttributeName, 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 // should still satisfy one of the valid syntaxes. - if (!TryParseBindAttribute(attributeName, out valueAttributeName, out changeAttributeName)) + if (!TryParseBindAttribute(bindEntry, out valueAttributeName, out changeAttributeName)) { 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. // // We expect 1 bind tag helper per-node. + var node = bindEntry.BindNode; + var attributeName = node.AttributeName; valueAttributeName = node.TagHelper.GetValueAttributeName() ?? valueAttributeName; changeAttributeName = node.TagHelper.GetChangeAttributeName() ?? changeAttributeName; 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().FirstOrDefault(); 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; } + } } } diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDiagnosticFactory.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDiagnosticFactory.cs index 7d21e6493e..b5eb7395c9 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDiagnosticFactory.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDiagnosticFactory.cs @@ -166,7 +166,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}9991", () => "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); 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); } + + 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; + } } } diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeDescriptor.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeDescriptor.cs index 597d721a96..bff46f4549 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeDescriptor.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeDescriptor.cs @@ -17,6 +17,7 @@ namespace Microsoft.AspNetCore.Razor.Language string indexerTypeName, string documentation, string displayName, + BoundAttributeParameterDescriptor[] parameterDescriptors, Dictionary metadata, RazorDiagnostic[] diagnostics) : base(kind) @@ -29,6 +30,7 @@ namespace Microsoft.AspNetCore.Razor.Language IndexerTypeName = indexerTypeName; Documentation = documentation; DisplayName = displayName; + BoundAttributeParameters = parameterDescriptors; Metadata = metadata; Diagnostics = diagnostics; diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeDescriptorBuilder.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeDescriptorBuilder.cs index 0652686dd2..8bf57e156a 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeDescriptorBuilder.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeDescriptorBuilder.cs @@ -31,6 +31,7 @@ namespace Microsoft.AspNetCore.Razor.Language private readonly DefaultTagHelperDescriptorBuilder _parent; private readonly string _kind; private readonly Dictionary _metadata; + private List _attributeParameterBuilders; private RazorDiagnosticCollection _diagnostics; @@ -73,6 +74,20 @@ namespace Microsoft.AspNetCore.Razor.Language } } + public override void BindAttributeParameter(Action configure) + { + if (configure == null) + { + throw new ArgumentNullException(nameof(configure)); + } + + EnsureAttributeParameterBuilders(); + + var builder = new DefaultBoundAttributeParameterDescriptorBuilder(this, _kind); + configure(builder); + _attributeParameterBuilders.Add(builder); + } + public BoundAttributeDescriptor Build() { var validationDiagnostics = Validate(); @@ -82,6 +97,19 @@ namespace Microsoft.AspNetCore.Razor.Language diagnostics.UnionWith(_diagnostics); } + var parameters = Array.Empty(); + if (_attributeParameterBuilders != null) + { + // Attribute parameters are case-sensitive. + var parameterset = new HashSet(BoundAttributeParameterDescriptorComparer.CaseSensitive); + for (var i = 0; i < _attributeParameterBuilders.Count; i++) + { + parameterset.Add(_attributeParameterBuilders[i].Build()); + } + + parameters = parameterset.ToArray(); + } + var descriptor = new DefaultBoundAttributeDescriptor( _kind, Name, @@ -92,6 +120,7 @@ namespace Microsoft.AspNetCore.Razor.Language IndexerValueTypeName, Documentation, GetDisplayName(), + parameters, new Dictionary(Metadata), diagnostics.ToArray()); @@ -205,5 +234,13 @@ namespace Microsoft.AspNetCore.Razor.Language } } } + + private void EnsureAttributeParameterBuilders() + { + if (_attributeParameterBuilders == null) + { + _attributeParameterBuilders = new List(); + } + } } } diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeParameterDescriptor.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeParameterDescriptor.cs new file mode 100644 index 0000000000..349ffb68f8 --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeParameterDescriptor.cs @@ -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 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"; + } + } +} diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeParameterDescriptorBuilder.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeParameterDescriptorBuilder.cs new file mode 100644 index 0000000000..d7c62286bc --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultBoundAttributeParameterDescriptorBuilder.cs @@ -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 _metadata; + + private RazorDiagnosticCollection _diagnostics; + + public DefaultBoundAttributeParameterDescriptorBuilder(DefaultBoundAttributeDescriptorBuilder parent, string kind) + { + _parent = parent; + _kind = kind; + + _metadata = new Dictionary(); + } + + 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 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(validationDiagnostics); + if (_diagnostics != null) + { + diagnostics.UnionWith(_diagnostics); + } + var descriptor = new DefaultBoundAttributeParameterDescriptor( + _kind, + Name, + TypeName, + IsEnum, + Documentation, + GetDisplayName(), + new Dictionary(Metadata), + diagnostics.ToArray()); + + return descriptor; + } + + private string GetDisplayName() + { + if (DisplayName != null) + { + return DisplayName; + } + + return $":{Name}"; + } + + private IEnumerable 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; + } + } + } + } + } +} diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorIntermediateNodeLoweringPhase.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorIntermediateNodeLoweringPhase.cs index cfefed3b4a..ebbc8b9148 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorIntermediateNodeLoweringPhase.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/DefaultRazorIntermediateNodeLoweringPhase.cs @@ -1716,6 +1716,7 @@ namespace Microsoft.AspNetCore.Razor.Language var descriptors = element.TagHelperInfo.BindingResult.Descriptors; var attributeName = node.Name.GetContent(); var attributeValueNode = node.Value; + var associatedDescriptors = descriptors.Where(descriptor => descriptor.BoundAttributes.Any(attributeDescriptor => TagHelperMatchingConventions.CanSatisfyBoundAttribute(attributeName, attributeDescriptor))); @@ -1723,24 +1724,47 @@ namespace Microsoft.AspNetCore.Razor.Language { 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() - { - AttributeName = attributeName, - BoundAttribute = associatedAttributeDescriptor, - TagHelper = associatedDescriptor, - AttributeStructure = node.TagHelperAttributeInfo.AttributeStructure, - Source = BuildSourceSpanFromNode(attributeValueNode), - IsIndexerNameMatch = TagHelperMatchingConventions.SatisfiesBoundAttributeIndexer(attributeName, associatedAttributeDescriptor), - }; - - _builder.Push(setTagHelperProperty); - VisitAttributeValue(attributeValueNode); - _builder.Pop(); + _builder.Push(attributeNode); + VisitAttributeValue(attributeValueNode); + _builder.Pop(); + } } } else diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/IntermediateNodeVisitor.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/IntermediateNodeVisitor.cs index 134294394d..e2e249ad2c 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/IntermediateNodeVisitor.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/IntermediateNodeVisitor.cs @@ -129,6 +129,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Intermediate VisitDefault(node); } + public virtual void VisitTagHelperAttributeParameter(TagHelperAttributeParameterIntermediateNode node) + { + VisitDefault(node); + } + public virtual void VisitComponent(ComponentIntermediateNode node) { VisitDefault(node); diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/TagHelperAttributeParameterIntermediateNode.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/TagHelperAttributeParameterIntermediateNode.cs new file mode 100644 index 0000000000..91466e44b0 --- /dev/null +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/TagHelperAttributeParameterIntermediateNode.cs @@ -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); + } + } +} diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/TagHelperBlockRewriter.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/TagHelperBlockRewriter.cs index a585b8781b..1516bfc4c3 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/TagHelperBlockRewriter.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/TagHelperBlockRewriter.cs @@ -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. private static string GetPropertyType(string name, IEnumerable descriptors) { - var firstBoundAttribute = FindFirstBoundAttribute(name, descriptors); - var isBoundToIndexer = TagHelperMatchingConventions.SatisfiesBoundAttributeIndexer(name, firstBoundAttribute); + foreach (var descriptor in descriptors) + { + 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 firstBoundAttribute?.IndexerTypeName; - } - else - { - return firstBoundAttribute?.TypeName; - } + return null; } // Create a TryParseResult for given name, filling in binding details. @@ -292,13 +297,39 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy IEnumerable descriptors, HashSet processedBoundAttributeNames) { - var firstBoundAttribute = FindFirstBoundAttribute(name, descriptors); - var isBoundAttribute = firstBoundAttribute != null; - var isBoundNonStringAttribute = isBoundAttribute && !firstBoundAttribute.ExpectsStringValue(name); - var isBoundBooleanAttribute = isBoundAttribute && firstBoundAttribute.ExpectsBooleanValue(name); - var isMissingDictionaryKey = isBoundAttribute && - firstBoundAttribute.IndexerNamePrefix != null && - name.Length == firstBoundAttribute.IndexerNamePrefix.Length; + var isBoundAttribute = false; + var isBoundNonStringAttribute = false; + var isBoundBooleanAttribute = false; + var isMissingDictionaryKey = false; + + foreach (var descriptor in descriptors) + { + 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; 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 descriptors) - { - var firstBoundAttribute = descriptors - .SelectMany(descriptor => descriptor.BoundAttributes) - .FirstOrDefault(attributeDescriptor => TagHelperMatchingConventions.CanSatisfyBoundAttribute(name, attributeDescriptor)); - - return firstBoundAttribute; - } - private static string GetAttributeValueContent(RazorSyntaxNode attributeBlock) { if (attributeBlock is MarkupTagHelperAttributeSyntax tagHelperAttribute) diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorDiagnosticFactory.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorDiagnosticFactory.cs index bd24339b2f..e174c45c23 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorDiagnosticFactory.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorDiagnosticFactory.cs @@ -779,6 +779,41 @@ namespace Microsoft.AspNetCore.Razor.Language 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 #region Rewriter Errors diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorDiagnosticSeverity.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorDiagnosticSeverity.cs index 025449f384..2f53ae99cb 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorDiagnosticSeverity.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/RazorDiagnosticSeverity.cs @@ -6,6 +6,7 @@ namespace Microsoft.AspNetCore.Razor.Language public enum RazorDiagnosticSeverity { // Purposely using the same value as Roslyn here. + Warning = 2, Error = 3, } } diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Resources.resx b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Resources.resx index b08df3e762..d2eb94338e 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Resources.resx +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Resources.resx @@ -541,4 +541,10 @@ Namespace + + 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. + + + Invalid tag helper bound attribute parameter '{0}'. Tag helpers cannot bind to HTML attribute parameters with a null or empty name. + \ No newline at end of file diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/TagHelperMatchingConventions.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/TagHelperMatchingConventions.cs index 1fb483c7ea..514acad767 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/TagHelperMatchingConventions.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/TagHelperMatchingConventions.cs @@ -128,7 +128,9 @@ namespace Microsoft.AspNetCore.Razor.Language 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) @@ -138,6 +140,84 @@ namespace Microsoft.AspNetCore.Razor.Language 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) { return string.Equals(descriptor.Name, name, StringComparison.OrdinalIgnoreCase); diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs index ba2740b7ae..9be0e8e632 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs @@ -644,7 +644,7 @@ namespace Test }")); // Act var generated = CompileToCSharp(@" - + @code { public int ParentValue { get; set; } = 42; }"); @@ -674,7 +674,7 @@ namespace Test }")); var generated = CompileToCSharp(@" - + @code { public int ParentValue { get; set; } = 42; }"); @@ -982,7 +982,7 @@ namespace Test // Act var generated = CompileToCSharp(@" - + @code { public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1); }"); @@ -1000,7 +1000,7 @@ namespace Test // Act var generated = CompileToCSharp(@" - + @code { public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1); @@ -1056,7 +1056,7 @@ namespace Test // Act var generated = CompileToCSharp(@" - + @code { public int ParentValue { get; set; } = 42; }"); @@ -1074,7 +1074,7 @@ namespace Test // Act var generated = CompileToCSharp(@" - + @code { public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1); }"); diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.codegen.cs index 87f27b3d18..3867a27f26 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.codegen.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.codegen.cs @@ -23,7 +23,7 @@ namespace Test __o = Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck(Microsoft.AspNetCore.Components.BindMethods.GetValue( #nullable restore #line 1 "x:\dir\subdir\Test\TestComponent.cshtml" - ParentValue + ParentValue #line default #line hidden diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.ir.txt index 3b8d1525ae..eff3bf473e 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.ir.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.ir.txt @@ -14,16 +14,16 @@ Document - CSharpCode - IntermediateToken - - CSharp - #pragma warning restore 0414 MethodDeclaration - - protected override - void - BuildRenderTree - Component - (0:0,0 [50] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - ComponentAttribute - (35:0,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - AttributeStructure.DoubleQuotes + Component - (0:0,0 [69] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent + ComponentAttribute - (25:0,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - AttributeStructure.DoubleQuotes CSharpExpression - 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 - ) - 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 - IntermediateToken - - CSharp - __value => ParentValue = __value - HtmlContent - (50:0,50 [2] x:\dir\subdir\Test\TestComponent.cshtml) - IntermediateToken - (50:0,50 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n - CSharpCode - (59: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 + HtmlContent - (69:0,69 [2] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (69:0,69 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n + CSharpCode - (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.mappings.txt index 81e5a357dd..1fad0343a1 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.mappings.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.mappings.txt @@ -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| -Generated Location: (1022:25,35 [11] ) +Generated Location: (1012:25,25 [11] ) |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; | -Generated Location: (1627:47,7 [50] ) +Generated Location: (1617:47,7 [50] ) | public int ParentValue { get; set; } = 42; | diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.codegen.cs index 656fc8534b..84daca5cb7 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.codegen.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.codegen.cs @@ -23,7 +23,7 @@ namespace Test __o = Microsoft.AspNetCore.Components.BindMethods.GetValue( #nullable restore #line 1 "x:\dir\subdir\Test\TestComponent.cshtml" - ParentValue + ParentValue #line default #line hidden diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.ir.txt index f3cedf3203..226ba4ea8e 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.ir.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.ir.txt @@ -14,16 +14,16 @@ Document - CSharpCode - IntermediateToken - - CSharp - #pragma warning restore 0414 MethodDeclaration - - protected override - void - BuildRenderTree - Component - (0:0,0 [50] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - ComponentAttribute - (35:0,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - AttributeStructure.DoubleQuotes + Component - (0:0,0 [69] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent + ComponentAttribute - (25:0,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - AttributeStructure.DoubleQuotes CSharpExpression - 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 - ) - 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 - IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => ParentValue = __value, ParentValue) - HtmlContent - (50:0,50 [2] x:\dir\subdir\Test\TestComponent.cshtml) - IntermediateToken - (50:0,50 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n - CSharpCode - (59: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 + HtmlContent - (69:0,69 [2] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (69:0,69 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n + CSharpCode - (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.mappings.txt index 231f240274..0f77b3a689 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.mappings.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.mappings.txt @@ -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| -Generated Location: (951:25,35 [11] ) +Generated Location: (941:25,25 [11] ) |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; | -Generated Location: (1595:46,7 [50] ) +Generated Location: (1585:46,7 [50] ) | public int ParentValue { get; set; } = 42; | diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.codegen.cs index 95f7a273d0..eaf0a8aae8 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.codegen.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.codegen.cs @@ -23,7 +23,7 @@ namespace Test __o = Microsoft.AspNetCore.Components.BindMethods.GetValue( #nullable restore #line 1 "x:\dir\subdir\Test\TestComponent.cshtml" - CurrentDate + CurrentDate #line default #line hidden diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.ir.txt index 526e3587b1..92b02ddb5a 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.ir.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.ir.txt @@ -14,21 +14,21 @@ Document - CSharpCode - IntermediateToken - - CSharp - #pragma warning restore 0414 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=" - " HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - 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 - - 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 - "MM/dd" 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 - - 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) - IntermediateToken - (77:0,77 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n - CSharpCode - (86: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 + HtmlContent - (101:0,101 [2] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (101:0,101 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n + CSharpCode - (110:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (110:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.mappings.txt index 031d39cb44..f70077ef5c 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.mappings.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.mappings.txt @@ -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| -Generated Location: (957:25,41 [11] ) +Generated Location: (948:25,32 [11] ) |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); | -Generated Location: (1320:36,7 [77] ) +Generated Location: (1311:36,7 [77] ) | public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1); | diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.codegen.cs index 1b9ea03181..4b3ecf0e64 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.codegen.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.codegen.cs @@ -23,7 +23,7 @@ namespace Test __o = Microsoft.AspNetCore.Components.BindMethods.GetValue( #nullable restore #line 1 "x:\dir\subdir\Test\TestComponent.cshtml" - ParentValue + ParentValue #line default #line hidden diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.ir.txt index e094fc08ec..9b37bd5daf 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.ir.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.ir.txt @@ -14,19 +14,19 @@ Document - CSharpCode - IntermediateToken - - CSharp - #pragma warning restore 0414 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=" - " HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - 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 - - 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 - ) - 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 - - IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => ParentValue = __value, ParentValue) - HtmlContent - (56:0,56 [2] x:\dir\subdir\Test\TestComponent.cshtml) - IntermediateToken - (56:0,56 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n - CSharpCode - (65: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 + HtmlContent - (75:0,75 [2] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (75:0,75 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n + CSharpCode - (84:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (84:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.mappings.txt index 8b3b1de528..daf85f2ae3 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.mappings.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.mappings.txt @@ -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| -Generated Location: (957:25,41 [11] ) +Generated Location: (948:25,32 [11] ) |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; | -Generated Location: (1302:36,7 [50] ) +Generated Location: (1293:36,7 [50] ) | public int ParentValue { get; set; } = 42; | diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.codegen.cs index a117c06d33..819736dad7 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.codegen.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.codegen.cs @@ -31,7 +31,7 @@ namespace Test , #nullable restore #line 1 "x:\dir\subdir\Test\TestComponent.cshtml" - Format + Format #line default #line hidden diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.ir.txt index c9a15a829c..84d1fc6bb0 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.ir.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.ir.txt @@ -14,7 +14,7 @@ Document - CSharpCode - IntermediateToken - - CSharp - #pragma warning restore 0414 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=" - " HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - 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 - (26:0,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate 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 - ) HtmlAttribute - (25:0,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - " CSharpExpressionAttributeValue - - 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) - IntermediateToken - (63:0,63 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n - CSharpCode - (72: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 + HtmlContent - (62:0,62 [2] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (62:0,62 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n + CSharpCode - (71:1,7 [135] x:\dir\subdir\Test\TestComponent.cshtml) + 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 diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.mappings.txt index 467143fcae..8fa58f7f1f 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.mappings.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.mappings.txt @@ -3,18 +3,18 @@ Source Location: (26:0,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) Generated Location: (942:25,26 [11] ) |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| -Generated Location: (1145:33,54 [6] ) +Generated Location: (1144:33,53 [6] ) |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 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); diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormat_WritesAttributes/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormat_WritesAttributes/TestComponent.ir.txt index 8cdcdf879a..d4468c828e 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormat_WritesAttributes/TestComponent.ir.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormat_WritesAttributes/TestComponent.ir.txt @@ -14,7 +14,7 @@ Document - CSharpCode - IntermediateToken - - CSharp - #pragma warning restore 0414 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=" - " HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - 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=" - " CSharpExpressionAttributeValue - - 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) - IntermediateToken - (66:0,66 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n - CSharpCode - (75: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 + HtmlContent - (65:0,65 [2] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (65:0,65 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n + CSharpCode - (74:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (74:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormat_WritesAttributes/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormat_WritesAttributes/TestComponent.mappings.txt index e339f220e7..4956ac6159 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormat_WritesAttributes/TestComponent.mappings.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormat_WritesAttributes/TestComponent.mappings.txt @@ -3,7 +3,7 @@ Source Location: (26:0,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) Generated Location: (942:25,26 [11] ) |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); | diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.codegen.cs index 8b79a36fee..4c89e98c42 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.codegen.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.codegen.cs @@ -17,7 +17,7 @@ namespace Test builder.AddAttribute(1, "Value", Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck(Microsoft.AspNetCore.Components.BindMethods.GetValue( #nullable restore #line 1 "x:\dir\subdir\Test\TestComponent.cshtml" - ParentValue + ParentValue #line default #line hidden diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.ir.txt index 1a0472f8d3..fa220494f8 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.ir.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.ir.txt @@ -7,14 +7,14 @@ Document - UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase - MethodDeclaration - - protected override - void - BuildRenderTree - Component - (0:0,0 [50] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - ComponentAttribute - (35:0,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - AttributeStructure.DoubleQuotes + Component - (0:0,0 [69] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent + ComponentAttribute - (25:0,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - AttributeStructure.DoubleQuotes CSharpExpression - 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 - ) - 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 - IntermediateToken - - CSharp - __value => ParentValue = __value - CSharpCode - (59: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 + CSharpCode - (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.mappings.txt index 95edc8e771..6e6cebdcdd 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.mappings.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithMatchingProperties/TestComponent.mappings.txt @@ -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; | -Generated Location: (1202:31,7 [50] ) +Generated Location: (1192:31,7 [50] ) | public int ParentValue { get; set; } = 42; | diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.codegen.cs index 17d6de2e61..64a178882f 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.codegen.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.codegen.cs @@ -17,7 +17,7 @@ namespace Test builder.AddAttribute(1, "Value", Microsoft.AspNetCore.Components.BindMethods.GetValue( #nullable restore #line 1 "x:\dir\subdir\Test\TestComponent.cshtml" - ParentValue + ParentValue #line default #line hidden diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.ir.txt index 149dd07593..f307ef9cba 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.ir.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.ir.txt @@ -7,14 +7,14 @@ Document - UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase - MethodDeclaration - - protected override - void - BuildRenderTree - Component - (0:0,0 [50] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - ComponentAttribute - (35:0,35 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - AttributeStructure.DoubleQuotes + Component - (0:0,0 [69] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent + ComponentAttribute - (25:0,25 [11] x:\dir\subdir\Test\TestComponent.cshtml) - Value - AttributeStructure.DoubleQuotes CSharpExpression - 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 - ) - 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 - IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => ParentValue = __value, ParentValue) - CSharpCode - (59: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 + CSharpCode - (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (78:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.mappings.txt index 3c5137f6b5..2eab550e84 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.mappings.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties/TestComponent.mappings.txt @@ -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; | -Generated Location: (1184:31,7 [50] ) +Generated Location: (1174:31,7 [50] ) | public int ParentValue { get; set; } = 42; | diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.codegen.cs index 7468db5040..fd94ca9573 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.codegen.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.codegen.cs @@ -18,7 +18,7 @@ namespace Test builder.AddAttribute(2, "value", Microsoft.AspNetCore.Components.BindMethods.GetValue( #nullable restore #line 1 "x:\dir\subdir\Test\TestComponent.cshtml" - CurrentDate + CurrentDate #line default #line hidden diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.ir.txt index f3287fdd97..ca7067e84f 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.ir.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.ir.txt @@ -7,19 +7,19 @@ Document - UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase - 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=" - " HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - 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 - - 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 - "MM/dd" 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 - - 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) - IntermediateToken - (86:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n + CSharpCode - (110:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (110:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.mappings.txt index e6d06aeaf1..6b18dfcea7 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.mappings.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WithFormat_WritesAttributes/TestComponent.mappings.txt @@ -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); | -Generated Location: (1248:32,7 [77] ) +Generated Location: (1239:32,7 [77] ) | public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1); | diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.codegen.cs index a0aa6809f4..5a71a7aba1 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.codegen.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.codegen.cs @@ -18,7 +18,7 @@ namespace Test builder.AddAttribute(2, "value", Microsoft.AspNetCore.Components.BindMethods.GetValue( #nullable restore #line 1 "x:\dir\subdir\Test\TestComponent.cshtml" - ParentValue + ParentValue #line default #line hidden diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.ir.txt index 35e51a87c6..45b1323b7d 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.ir.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.ir.txt @@ -7,17 +7,17 @@ Document - UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase - 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=" - " HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - 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 - - 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 - ) - 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 - - IntermediateToken - - CSharp - Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => ParentValue = __value, ParentValue) - CSharpCode - (65: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 + CSharpCode - (84:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (84:1,7 [50] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public int ParentValue { get; set; } = 42;\n diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.mappings.txt index 580244f905..f88931b97f 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.mappings.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BindToElementFallback_WritesAttributes/TestComponent.mappings.txt @@ -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; | -Generated Location: (1230:32,7 [50] ) +Generated Location: (1221:32,7 [50] ) | public int ParentValue { get; set; } = 42; | diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.codegen.cs index c143f3dfa8..1708507077 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.codegen.cs +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.codegen.cs @@ -26,7 +26,7 @@ namespace Test , #nullable restore #line 1 "x:\dir\subdir\Test\TestComponent.cshtml" - Format + Format #line default #line hidden diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.ir.txt index 0456e35fab..f17f9d6d5d 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.ir.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.ir.txt @@ -7,7 +7,7 @@ Document - UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase - 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=" - " HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - 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 - (26:0,26 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - CurrentDate 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 - ) HtmlAttribute - (25:0,25 [12] x:\dir\subdir\Test\TestComponent.cshtml) - onchange=" - " CSharpExpressionAttributeValue - - 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) - 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 + CSharpCode - (71:1,7 [135] x:\dir\subdir\Test\TestComponent.cshtml) + 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 diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.mappings.txt index 6c715d821c..2bae793571 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.mappings.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormatFromProperty_WritesAttributes/TestComponent.mappings.txt @@ -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 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); diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormat_WritesAttributes/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormat_WritesAttributes/TestComponent.ir.txt index 18dea4fcb3..06547b365a 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormat_WritesAttributes/TestComponent.ir.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormat_WritesAttributes/TestComponent.ir.txt @@ -7,7 +7,7 @@ Document - UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Components.ComponentBase - 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=" - " HtmlAttributeValue - (13:0,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - 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=" - " CSharpExpressionAttributeValue - - 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) - IntermediateToken - (75:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n + CSharpCode - (74:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml) + IntermediateToken - (74:1,7 [77] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public DateTime CurrentDate { get; set; } = new DateTime(2018, 1, 1);\n diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormat_WritesAttributes/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormat_WritesAttributes/TestComponent.mappings.txt index a1f634d6af..da960879b4 100644 --- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormat_WritesAttributes/TestComponent.mappings.txt +++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentRuntimeCodeGenerationTest/BuiltIn_BindToInputText_WithFormat_WritesAttributes/TestComponent.mappings.txt @@ -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); | diff --git a/src/Razor/Microsoft.CodeAnalysis.Razor/src/BindTagHelperDescriptorProvider.cs b/src/Razor/Microsoft.CodeAnalysis.Razor/src/BindTagHelperDescriptorProvider.cs index f055cc3bfd..33113ec30f 100644 --- a/src/Razor/Microsoft.CodeAnalysis.Razor/src/BindTagHelperDescriptorProvider.cs +++ b/src/Razor/Microsoft.CodeAnalysis.Razor/src/BindTagHelperDescriptorProvider.cs @@ -46,7 +46,7 @@ namespace Microsoft.CodeAnalysis.Razor // // 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. // // 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.Name = "bind-..."; + var attributeName = "bind-..."; + attribute.Name = attributeName; attribute.AsDictionary("bind-", typeof(object).FullName); // 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. attribute.SetPropertyName("Bind"); attribute.TypeName = "System.Collections.Generic.Dictionary"; + + 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 => { attribute.Documentation = ComponentResources.BindTagHelper_Fallback_Format_Documentation; @@ -237,6 +257,7 @@ namespace Microsoft.CodeAnalysis.Razor return results; } + private List CreateElementBindTagHelpers(List data) { var results = new List(); @@ -251,6 +272,8 @@ namespace Microsoft.CodeAnalysis.Razor var formatName = 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); builder.Documentation = string.Format( 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 // a C# property will crash trying to create the toolips. 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 => { - attribute.Documentation = string.Format(ComponentResources.BindTagHelper_Element_Format_Documentation, attributeName); - attribute.Name = formatAttributeName; 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 // a C# property will crash trying to create the toolips. @@ -376,7 +417,6 @@ namespace Microsoft.CodeAnalysis.Razor if (tagHelper.BoundAttributes[j].Name == valueAttributeName) { valueAttribute = tagHelper.BoundAttributes[j]; - } if (tagHelper.BoundAttributes[j].Name == expressionAttributeName) diff --git a/src/Razor/Microsoft.CodeAnalysis.Razor/test/BindTagHelperDescriptorProviderTest.cs b/src/Razor/Microsoft.CodeAnalysis.Razor/test/BindTagHelperDescriptorProviderTest.cs index 0265459112..f44969d253 100644 --- a/src/Razor/Microsoft.CodeAnalysis.Razor/test/BindTagHelperDescriptorProviderTest.cs +++ b/src/Razor/Microsoft.CodeAnalysis.Razor/test/BindTagHelperDescriptorProviderTest.cs @@ -395,33 +395,28 @@ namespace Test Assert.False(attribute.IsBooleanProperty); 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 - Assert.Empty(attribute.Diagnostics); - Assert.False(attribute.HasErrors); - Assert.Equal(ComponentMetadata.Bind.TagHelperKind, attribute.Kind); - Assert.False(attribute.IsDefaultKind()); - Assert.False(attribute.HasIndexer); - Assert.Null(attribute.IndexerNamePrefix); - Assert.Null(attribute.IndexerTypeName); - Assert.False(attribute.IsIndexerBooleanProperty); - Assert.False(attribute.IsIndexerStringProperty); + Assert.Empty(parameter.Diagnostics); + Assert.False(parameter.HasErrors); + Assert.Equal(ComponentMetadata.Bind.TagHelperKind, parameter.Kind); + Assert.False(parameter.IsDefaultKind()); Assert.Equal( "Specifies a format to convert the value specified by the 'bind' attribute. " + "The format string can currently only be used with expressions of type DateTime.", - attribute.Documentation); + parameter.Documentation); - Assert.Equal("format-myprop", attribute.Name); - Assert.Equal("Format_myprop", attribute.GetPropertyName()); - Assert.Equal("string Test.BindAttributes.Format_myprop", attribute.DisplayName); + Assert.Equal("format", parameter.Name); + Assert.Equal("Format_myprop", parameter.GetPropertyName()); + Assert.Equal(":format", parameter.DisplayName); // Defined from the property type - Assert.Equal("System.String", attribute.TypeName); - Assert.True(attribute.IsStringProperty); - Assert.False(attribute.IsBooleanProperty); - Assert.False(attribute.IsEnum); + Assert.Equal("System.String", parameter.TypeName); + Assert.True(parameter.IsStringProperty); + Assert.False(parameter.IsBooleanProperty); + Assert.False(parameter.IsEnum); } [Fact] @@ -529,10 +524,10 @@ namespace Test Assert.Equal("Bind", attribute.GetPropertyName()); Assert.Equal("object Test.BindAttributes.Bind", attribute.DisplayName); - attribute = Assert.Single(bind.BoundAttributes, a => a.Name.StartsWith("format")); - Assert.Equal("format-myprop", attribute.Name); - Assert.Equal("Format_myprop", attribute.GetPropertyName()); - Assert.Equal("string Test.BindAttributes.Format_myprop", attribute.DisplayName); + var parameter = Assert.Single(attribute.BoundAttributeParameters, a => a.Name.Equals("format")); + Assert.Equal("format", parameter.Name); + Assert.Equal("Format_myprop", parameter.GetPropertyName()); + Assert.Equal(":format", parameter.DisplayName); } [Fact] @@ -597,10 +592,10 @@ namespace Test Assert.Equal("Bind", attribute.GetPropertyName()); Assert.Equal("object Test.BindAttributes.Bind", attribute.DisplayName); - attribute = Assert.Single(bind.BoundAttributes, a => a.Name.StartsWith("format")); - Assert.Equal("format-myprop", attribute.Name); - Assert.Equal("Format_myprop", attribute.GetPropertyName()); - Assert.Equal("string Test.BindAttributes.Format_myprop", attribute.DisplayName); + var parameter = Assert.Single(attribute.BoundAttributeParameters, a => a.Name.Equals("format")); + Assert.Equal("format", parameter.Name); + Assert.Equal("Format_myprop", parameter.GetPropertyName()); + Assert.Equal(":format", parameter.DisplayName); } [Fact] @@ -665,10 +660,10 @@ namespace Test Assert.Equal("Bind_somevalue", attribute.GetPropertyName()); Assert.Equal("object Test.BindAttributes.Bind_somevalue", attribute.DisplayName); - attribute = Assert.Single(bind.BoundAttributes, a => a.Name.StartsWith("format")); - Assert.Equal("format-somevalue", attribute.Name); - Assert.Equal("Format_somevalue", attribute.GetPropertyName()); - Assert.Equal("string Test.BindAttributes.Format_somevalue", attribute.DisplayName); + var parameter = Assert.Single(attribute.BoundAttributeParameters, a => a.Name.Equals("format")); + Assert.Equal("format", parameter.Name); + Assert.Equal("Format_somevalue", parameter.GetPropertyName()); + Assert.Equal(":format", parameter.DisplayName); } [Fact] @@ -710,7 +705,7 @@ namespace Test Assert.Equal( "Binds the provided expression to an attribute and a change event, based on the naming of " + - "the bind attribute. For example: bind-value-onchange=\"...\" will assign the " + + "the bind attribute. For example: bind-value=\"...\" and bind-value:event=\"onchange\" 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.", bind.Documentation); @@ -753,7 +748,7 @@ namespace Test Assert.Equal( "Binds the provided expression to an attribute and a change event, based on the naming of " + - "the bind attribute. For example: bind-value-onchange=\"...\" will assign the " + + "the bind attribute. For example: bind-value=\"...\" and bind-value:event=\"onchange\" 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.", attribute.Documentation); @@ -770,37 +765,30 @@ namespace Test Assert.False(attribute.IsBooleanProperty); 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 - Assert.Empty(attribute.Diagnostics); - Assert.False(attribute.HasErrors); - Assert.Equal(ComponentMetadata.Bind.TagHelperKind, attribute.Kind); - Assert.False(attribute.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.Empty(parameter.Diagnostics); + Assert.False(parameter.HasErrors); + Assert.Equal(ComponentMetadata.Bind.TagHelperKind, parameter.Kind); + Assert.False(parameter.IsDefaultKind()); Assert.Equal( "Specifies a format to convert the value specified by the corresponding bind attribute. " + - "For example: format-value=\"...\" will apply a format string to the value " + - "specified in bind-value-.... The format string can currently only be used with " + + "For example: bind-value:format=\"...\" will apply a format string to the value " + + "specified in bind-value=\"...\". The format string can currently only be used with " + "expressions of type DateTime.", - attribute.Documentation); + parameter.Documentation); - Assert.Equal("format-...", attribute.Name); - Assert.Equal("Format", attribute.GetPropertyName()); - Assert.Equal( - "System.Collections.Generic.Dictionary Microsoft.AspNetCore.Components.Bind.Format", - attribute.DisplayName); + Assert.Equal("format", parameter.Name); + Assert.Equal("Format", parameter.GetPropertyName()); + Assert.Equal(":format", parameter.DisplayName); // Defined from the property type - Assert.Equal("System.Collections.Generic.Dictionary", attribute.TypeName); - Assert.False(attribute.IsStringProperty); - Assert.False(attribute.IsBooleanProperty); - Assert.False(attribute.IsEnum); + Assert.Equal("System.String", parameter.TypeName); + Assert.True(parameter.IsStringProperty); + Assert.False(parameter.IsBooleanProperty); + Assert.False(parameter.IsEnum); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/IntermediateNodeWriter.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/IntermediateNodeWriter.cs index c83dbb7c79..38f3e0e31f 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/IntermediateNodeWriter.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/IntermediateNodeWriter.cs @@ -128,6 +128,11 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests 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) { WriteContentNode(node, node.TagName);