diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/TagHelperDescriptorExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/TagHelperDescriptorExtensions.cs new file mode 100644 index 0000000000..dd32c0b013 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/TagHelperDescriptorExtensions.cs @@ -0,0 +1,37 @@ +// 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 Microsoft.AspNetCore.Razor.Language; + +namespace Microsoft.AspNetCore.Mvc.Razor.Extensions +{ + public static class TagHelperDescriptorExtensions + { + /// + /// Indicates whether a represents a view component. + /// + /// The to check. + /// Whether a represents a view component. + public static bool IsViewComponentKind(this TagHelperDescriptor tagHelper) + { + if (tagHelper == null) + { + throw new ArgumentNullException(nameof(tagHelper)); + } + + return string.Equals(ViewComponentTagHelperConventions.Kind, tagHelper.Kind, StringComparison.Ordinal); + } + + public static string GetViewComponentName(this TagHelperDescriptor tagHelper) + { + if (tagHelper == null) + { + throw new ArgumentNullException(nameof(tagHelper)); + } + + tagHelper.Metadata.TryGetValue(ViewComponentTagHelperMetadata.Name, out var result); + return result; + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperConventions.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperConventions.cs new file mode 100644 index 0000000000..fa7563d37b --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperConventions.cs @@ -0,0 +1,10 @@ +// 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. + +namespace Microsoft.AspNetCore.Mvc.Razor.Extensions +{ + public static class ViewComponentTagHelperConventions + { + public static readonly string Kind = "MVC.ViewComponent"; + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperDescriptorConventions.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperDescriptorConventions.cs deleted file mode 100644 index 63bb660c65..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperDescriptorConventions.cs +++ /dev/null @@ -1,27 +0,0 @@ -// 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 Microsoft.AspNetCore.Razor.Language; - -namespace Microsoft.AspNetCore.Mvc.Razor.Extensions -{ - /// - /// A library of methods used to generate s for view components. - /// - public static class ViewComponentTagHelperDescriptorConventions - { - /// - /// The key in a containing - /// the short name of a view component. - /// - public static readonly string ViewComponentNameKey = "ViewComponentName"; - - /// - /// Indicates whether a represents a view component. - /// - /// The to check. - /// Whether a represents a view component. - public static bool IsViewComponentDescriptor(TagHelperDescriptor descriptor) => - descriptor != null && descriptor.Metadata.ContainsKey(ViewComponentNameKey); - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperDescriptorFactory.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperDescriptorFactory.cs index 7bc925d292..b3e64c465a 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperDescriptorFactory.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperDescriptorFactory.cs @@ -56,7 +56,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions var tagName = $"vc:{HtmlConventions.ToHtmlCase(shortName)}"; var typeName = $"__Generated__{shortName}ViewComponentTagHelper"; var displayName = shortName + "ViewComponentTagHelper"; - var descriptorBuilder = TagHelperDescriptorBuilder.Create(typeName, assemblyName) + var descriptorBuilder = TagHelperDescriptorBuilder.Create(ViewComponentTagHelperConventions.Kind, typeName, assemblyName) + .TypeName(typeName) .DisplayName(displayName); if (TryFindInvokeMethod(type, out var method, out var diagnostic)) @@ -75,7 +76,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions descriptorBuilder.AddDiagnostic(diagnostic); } - descriptorBuilder.AddMetadata(ViewComponentTypes.ViewComponentNameKey, shortName); + descriptorBuilder.AddMetadata(ViewComponentTagHelperMetadata.Name, shortName); var descriptor = descriptorBuilder.Build(); return descriptor; @@ -152,7 +153,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions return true; } - private void AddRequiredAttributes(ImmutableArray methodParameters, TagMatchingRuleBuilder builder) + private void AddRequiredAttributes(ImmutableArray methodParameters, TagMatchingRuleDescriptorBuilder builder) { foreach (var parameter in methodParameters) { diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperMetadata.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperMetadata.cs new file mode 100644 index 0000000000..c4dd39918c --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperMetadata.cs @@ -0,0 +1,14 @@ +// 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. + +namespace Microsoft.AspNetCore.Mvc.Razor.Extensions +{ + public class ViewComponentTagHelperMetadata + { + /// + /// The key in a containing + /// the short name of a view component. + /// + public static readonly string Name = "MVC.ViewComponent.Name"; + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperPass.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperPass.cs index 96922b9a78..956413b66e 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperPass.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTagHelperPass.cs @@ -82,14 +82,14 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions ClassDeclarationIntermediateNode @class, TagHelperDescriptor tagHelper) { - var vcName = tagHelper.Metadata[ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey]; + var vcName = tagHelper.GetViewComponentName(); return $"{@namespace.Content}.{@class.Name}.__Generated__{vcName}ViewComponentTagHelper"; } private static string GetVCTHClassName( TagHelperDescriptor tagHelper) { - var vcName = tagHelper.Metadata[ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey]; + var vcName = tagHelper.GetViewComponentName(); return $"__Generated__{vcName}ViewComponentTagHelper"; } @@ -201,13 +201,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions private string[] GetMethodParameters(TagHelperDescriptor descriptor) { - var propertyNames = descriptor.BoundAttributes.Select( - attribute => attribute.GetPropertyName()); + var propertyNames = descriptor.BoundAttributes.Select(attribute => attribute.GetPropertyName()); var joinedPropertyNames = string.Join(", ", propertyNames); var parametersString = $"new {{ { joinedPropertyNames } }}"; - var viewComponentName = descriptor.Metadata[ - ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey]; + var viewComponentName = descriptor.GetViewComponentName(); var methodParameters = new[] { $"\"{viewComponentName}\"", parametersString }; return methodParameters; } @@ -239,10 +237,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions public override void VisitCreateTagHelper(CreateTagHelperIntermediateNode node) { var tagHelper = node.Descriptor; - if (ViewComponentTagHelperDescriptorConventions.IsViewComponentDescriptor(tagHelper)) + if (tagHelper.IsViewComponentKind()) { // Capture all the VCTagHelpers (unique by type name) so we can generate a class for each one. - var vcName = tagHelper.Metadata[ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey]; + var vcName = tagHelper.GetViewComponentName(); TagHelpers[vcName] = tagHelper; CreateTagHelpers.Add(new IntermediateNodeReference(Parent, node)); diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTypes.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTypes.cs index 2fab7878fa..5558ba5e06 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTypes.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/ViewComponentTypes.cs @@ -23,8 +23,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions public const string IDictionary = "System.Collections.Generic.IDictionary`2"; - public const string ViewComponentNameKey = "ViewComponentName"; - public const string AsyncMethodName = "InvokeAsync"; public const string SyncMethodName = "Invoke"; diff --git a/src/Microsoft.AspNetCore.Razor.Language/BoundAttributeDescriptor.cs b/src/Microsoft.AspNetCore.Razor.Language/BoundAttributeDescriptor.cs index 03a8342a6d..2014a1336f 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/BoundAttributeDescriptor.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/BoundAttributeDescriptor.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; namespace Microsoft.AspNetCore.Razor.Language @@ -10,6 +11,7 @@ namespace Microsoft.AspNetCore.Razor.Language /// /// A metadata class describing a tag helper attribute. /// + [DebuggerDisplay("{DisplayName,nq}")] public abstract class BoundAttributeDescriptor : IEquatable { protected BoundAttributeDescriptor(string kind) diff --git a/src/Microsoft.AspNetCore.Razor.Language/BoundAttributeDescriptorBuilder.cs b/src/Microsoft.AspNetCore.Razor.Language/BoundAttributeDescriptorBuilder.cs index 29d1daf87d..188d0a8ac5 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/BoundAttributeDescriptorBuilder.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/BoundAttributeDescriptorBuilder.cs @@ -1,301 +1,27 @@ // 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 sealed class BoundAttributeDescriptorBuilder + public abstract class BoundAttributeDescriptorBuilder { - internal const string DescriptorKind = "ITagHelper"; - internal const string PropertyNameKey = "ITagHelper.PropertyName"; + public abstract BoundAttributeDescriptorBuilder Name(string name); - private static readonly IReadOnlyDictionary PrimitiveDisplayTypeNameLookups = new Dictionary(StringComparer.Ordinal) - { - [typeof(byte).FullName] = "byte", - [typeof(sbyte).FullName] = "sbyte", - [typeof(int).FullName] = "int", - [typeof(uint).FullName] = "uint", - [typeof(short).FullName] = "short", - [typeof(ushort).FullName] = "ushort", - [typeof(long).FullName] = "long", - [typeof(ulong).FullName] = "ulong", - [typeof(float).FullName] = "float", - [typeof(double).FullName] = "double", - [typeof(char).FullName] = "char", - [typeof(bool).FullName] = "bool", - [typeof(object).FullName] = "object", - [typeof(string).FullName] = "string", - [typeof(decimal).FullName] = "decimal", - }; + public abstract BoundAttributeDescriptorBuilder PropertyName(string propertyName); - private string _displayName; - private bool _isEnum; - private bool _hasIndexer; - private string _indexerValueTypeName; - private string _name; - private string _propertyName; - private string _typeName; - private string _documentation; - private string _indexerNamePrefix; - private readonly string _containingTypeName; - private readonly Dictionary _metadata; - private HashSet _diagnostics; + public abstract BoundAttributeDescriptorBuilder TypeName(string typeName); - private BoundAttributeDescriptorBuilder(string containingTypeName) - { - _containingTypeName = containingTypeName; - _metadata = new Dictionary(); - } + public abstract BoundAttributeDescriptorBuilder AsEnum(); - public static BoundAttributeDescriptorBuilder Create(string containingTypeName) - { - return new BoundAttributeDescriptorBuilder(containingTypeName); - } + public abstract BoundAttributeDescriptorBuilder AsDictionary(string attributeNamePrefix, string valueTypeName); - public BoundAttributeDescriptorBuilder Name(string name) - { - _name = name; + public abstract BoundAttributeDescriptorBuilder Documentation(string documentation); - return this; - } + public abstract BoundAttributeDescriptorBuilder AddMetadata(string key, string value); - public BoundAttributeDescriptorBuilder PropertyName(string propertyName) - { - _propertyName = propertyName; + public abstract BoundAttributeDescriptorBuilder AddDiagnostic(RazorDiagnostic diagnostic); - return this; - } + public abstract BoundAttributeDescriptorBuilder DisplayName(string displayName); - public BoundAttributeDescriptorBuilder TypeName(string typeName) - { - _typeName = typeName; - - return this; - } - - public BoundAttributeDescriptorBuilder AsEnum() - { - _isEnum = true; - - return this; - } - - public BoundAttributeDescriptorBuilder AsDictionary(string attributeNamePrefix, string valueTypeName) - { - _indexerNamePrefix = attributeNamePrefix; - _indexerValueTypeName = valueTypeName; - _hasIndexer = true; - - return this; - } - - public BoundAttributeDescriptorBuilder Documentation(string documentation) - { - _documentation = documentation; - - return this; - } - - public BoundAttributeDescriptorBuilder AddMetadata(string key, string value) - { - _metadata[key] = value; - - return this; - } - - public BoundAttributeDescriptorBuilder AddDiagnostic(RazorDiagnostic diagnostic) - { - EnsureDiagnostics(); - _diagnostics.Add(diagnostic); - - return this; - } - - public BoundAttributeDescriptorBuilder DisplayName(string displayName) - { - if (displayName == null) - { - throw new ArgumentNullException(nameof(displayName)); - } - - _displayName = displayName; - - return this; - } - - public BoundAttributeDescriptor Build() - { - var validationDiagnostics = Validate(); - var diagnostics = new HashSet(validationDiagnostics); - if (_diagnostics != null) - { - diagnostics.UnionWith(_diagnostics); - } - - var displayName = _displayName; - if (displayName == null) - { - if (!PrimitiveDisplayTypeNameLookups.TryGetValue(_typeName, out var simpleName)) - { - simpleName = _typeName; - } - - displayName = $"{simpleName} {_containingTypeName}.{_propertyName}"; - } - - var descriptor = new ITagHelperBoundAttributeDescriptor( - _isEnum, - _name, - _propertyName, - _typeName, - _indexerNamePrefix, - _indexerValueTypeName, - _hasIndexer, - _documentation, - displayName, - _metadata, - diagnostics); - - return descriptor; - } - - public void Reset() - { - _name = null; - _propertyName = null; - _typeName = null; - _documentation = null; - _isEnum = false; - _indexerNamePrefix = null; - _indexerValueTypeName = null; - _metadata.Clear(); - _diagnostics?.Clear(); - } - - private IEnumerable Validate() - { - // data-* attributes are explicitly not implemented by user agents and are not intended for use on - // the server; therefore it's invalid for TagHelpers to bind to them. - const string DataDashPrefix = "data-"; - - if (string.IsNullOrWhiteSpace(_name)) - { - if (_indexerNamePrefix == null) - { - var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributeNullOrWhitespace( - _containingTypeName, - _propertyName); - - yield return diagnostic; - } - } - else - { - if (_name.StartsWith(DataDashPrefix, StringComparison.OrdinalIgnoreCase)) - { - var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributeNameStartsWith( - _containingTypeName, - _propertyName, - _name); - - yield return diagnostic; - } - - foreach (var character in _name) - { - if (char.IsWhiteSpace(character) || HtmlConventions.InvalidNonWhitespaceHtmlCharacters.Contains(character)) - { - var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributeName( - _containingTypeName, - _propertyName, - _name, - character); - - yield return diagnostic; - } - } - } - - if (_indexerNamePrefix != null) - { - if (_indexerNamePrefix.StartsWith(DataDashPrefix, StringComparison.OrdinalIgnoreCase)) - { - var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributePrefixStartsWith( - _containingTypeName, - _propertyName, - _indexerNamePrefix); - - yield return diagnostic; - } - else if (_indexerNamePrefix.Length > 0 && string.IsNullOrWhiteSpace(_indexerNamePrefix)) - { - var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributeNullOrWhitespace( - _containingTypeName, - _propertyName); - - yield return diagnostic; - } - else - { - foreach (var character in _indexerNamePrefix) - { - if (char.IsWhiteSpace(character) || HtmlConventions.InvalidNonWhitespaceHtmlCharacters.Contains(character)) - { - var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributePrefix( - _containingTypeName, - _propertyName, - _indexerNamePrefix, - character); - - yield return diagnostic; - } - } - } - } - } - - private void EnsureDiagnostics() - { - if (_diagnostics == null) - { - _diagnostics = new HashSet(); - } - } - - private class ITagHelperBoundAttributeDescriptor : BoundAttributeDescriptor - { - public ITagHelperBoundAttributeDescriptor( - bool isEnum, - string name, - string propertyName, - string typeName, - string dictionaryAttributeNamePrefix, - string dictionaryValueTypeName, - bool hasIndexer, - string documentation, - string displayName, - Dictionary metadata, - IEnumerable diagnostics) : base(DescriptorKind) - { - IsEnum = isEnum; - IsIndexerStringProperty = dictionaryValueTypeName == typeof(string).FullName || dictionaryValueTypeName == "string"; - IsStringProperty = typeName == typeof(string).FullName || typeName == "string"; - Name = name; - TypeName = typeName; - IndexerNamePrefix = dictionaryAttributeNamePrefix; - IndexerTypeName = dictionaryValueTypeName; - HasIndexer = hasIndexer; - Documentation = documentation; - DisplayName = displayName; - Diagnostics = new List(diagnostics); - Metadata = new Dictionary(metadata) - { - [PropertyNameKey] = propertyName - }; - } - } } } diff --git a/src/Microsoft.AspNetCore.Razor.Language/BoundAttributeDescriptorExtensions.cs b/src/Microsoft.AspNetCore.Razor.Language/BoundAttributeDescriptorExtensions.cs index 137b605abd..e1bab599f2 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/BoundAttributeDescriptorExtensions.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/BoundAttributeDescriptorExtensions.cs @@ -9,12 +9,14 @@ namespace Microsoft.AspNetCore.Razor.Language { public static string GetPropertyName(this BoundAttributeDescriptor descriptor) { - descriptor.Metadata.TryGetValue(BoundAttributeDescriptorBuilder.PropertyNameKey, out var propertyName); + descriptor.Metadata.TryGetValue(TagHelperMetadata.Common.PropertyName, out var propertyName); return propertyName; } public static bool IsDefaultKind(this BoundAttributeDescriptor descriptor) - => string.Equals(descriptor.Kind, BoundAttributeDescriptorBuilder.DescriptorKind, StringComparison.Ordinal); + { + return string.Equals(descriptor.Kind, TagHelperConventions.DefaultKind, StringComparison.Ordinal); + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Razor.Language/DefaultBoundAttributeDescriptor.cs b/src/Microsoft.AspNetCore.Razor.Language/DefaultBoundAttributeDescriptor.cs new file mode 100644 index 0000000000..6389a49310 --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Language/DefaultBoundAttributeDescriptor.cs @@ -0,0 +1,40 @@ +// 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 DefaultBoundAttributeDescriptor : BoundAttributeDescriptor + { + public DefaultBoundAttributeDescriptor( + string kind, + string name, + string typeName, + bool isEnum, + bool hasIndexer, + string indexerNamePrefix, + string indexerTypeName, + string documentation, + string displayName, + Dictionary metadata, + RazorDiagnostic[] diagnostics) + : base(kind) + { + Name = name; + TypeName = typeName; + IsEnum = isEnum; + HasIndexer = hasIndexer; + IndexerNamePrefix = indexerNamePrefix; + IndexerTypeName = indexerTypeName; + Documentation = documentation; + DisplayName = displayName; + + Metadata = metadata; + Diagnostics = diagnostics; + + IsIndexerStringProperty = indexerTypeName == typeof(string).FullName || indexerTypeName == "string"; + IsStringProperty = typeName == typeof(string).FullName || typeName == "string"; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Razor.Language/DefaultBoundAttributeDescriptorBuilder.cs b/src/Microsoft.AspNetCore.Razor.Language/DefaultBoundAttributeDescriptorBuilder.cs new file mode 100644 index 0000000000..da021c52d6 --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Language/DefaultBoundAttributeDescriptorBuilder.cs @@ -0,0 +1,262 @@ +// 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 DefaultBoundAttributeDescriptorBuilder : BoundAttributeDescriptorBuilder + { + private static readonly IReadOnlyDictionary PrimitiveDisplayTypeNameLookups = new Dictionary(StringComparer.Ordinal) + { + [typeof(byte).FullName] = "byte", + [typeof(sbyte).FullName] = "sbyte", + [typeof(int).FullName] = "int", + [typeof(uint).FullName] = "uint", + [typeof(short).FullName] = "short", + [typeof(ushort).FullName] = "ushort", + [typeof(long).FullName] = "long", + [typeof(ulong).FullName] = "ulong", + [typeof(float).FullName] = "float", + [typeof(double).FullName] = "double", + [typeof(char).FullName] = "char", + [typeof(bool).FullName] = "bool", + [typeof(object).FullName] = "object", + [typeof(string).FullName] = "string", + [typeof(decimal).FullName] = "decimal", + }; + + private readonly DefaultTagHelperDescriptorBuilder _parent; + private readonly string _kind; + + private string _displayName; + private bool _isEnum; + private bool _hasIndexer; + private string _indexerValueTypeName; + private string _name; + private string _typeName; + private string _documentation; + private string _indexerNamePrefix; + private readonly Dictionary _metadata; + private HashSet _diagnostics; + + public DefaultBoundAttributeDescriptorBuilder(DefaultTagHelperDescriptorBuilder parent, string kind) + { + _parent = parent; + _kind = kind; + + _metadata = new Dictionary(); + } + + public override BoundAttributeDescriptorBuilder Name(string name) + { + _name = name; + + return this; + } + + public override BoundAttributeDescriptorBuilder PropertyName(string propertyName) + { + _metadata[TagHelperMetadata.Common.PropertyName] = propertyName; + + return this; + } + + public override BoundAttributeDescriptorBuilder TypeName(string typeName) + { + _typeName = typeName; + + return this; + } + + public override BoundAttributeDescriptorBuilder AsEnum() + { + _isEnum = true; + + return this; + } + + public override BoundAttributeDescriptorBuilder AsDictionary(string attributeNamePrefix, string valueTypeName) + { + _indexerNamePrefix = attributeNamePrefix; + _indexerValueTypeName = valueTypeName; + _hasIndexer = true; + + return this; + } + + public override BoundAttributeDescriptorBuilder Documentation(string documentation) + { + _documentation = documentation; + + return this; + } + + public override BoundAttributeDescriptorBuilder AddMetadata(string key, string value) + { + _metadata[key] = value; + + return this; + } + + public override BoundAttributeDescriptorBuilder AddDiagnostic(RazorDiagnostic diagnostic) + { + EnsureDiagnostics(); + _diagnostics.Add(diagnostic); + + return this; + } + + public override BoundAttributeDescriptorBuilder DisplayName(string displayName) + { + if (displayName == null) + { + throw new ArgumentNullException(nameof(displayName)); + } + + _displayName = displayName; + + return this; + } + + public BoundAttributeDescriptor Build() + { + var validationDiagnostics = Validate(); + var diagnostics = new HashSet(validationDiagnostics); + if (_diagnostics != null) + { + diagnostics.UnionWith(_diagnostics); + } + + var descriptor = new DefaultBoundAttributeDescriptor( + _kind, + _name, + _typeName, + _isEnum, + _hasIndexer, + _indexerNamePrefix, + _indexerValueTypeName, + _documentation, + GetDisplayName(), + new Dictionary(_metadata), + diagnostics.ToArray()); + + return descriptor; + } + + private string GetDisplayName() + { + if (_displayName != null) + { + return _displayName; + } + + if (_typeName != null && + _metadata.ContainsKey(TagHelperMetadata.Common.PropertyName) && + _parent.Metadata.ContainsKey(TagHelperMetadata.Common.TypeName)) + { + // This looks like a normal c# property, so lets compute a display name based on that. + if (!PrimitiveDisplayTypeNameLookups.TryGetValue(_typeName, out var simpleTypeName)) + { + simpleTypeName = _typeName; + } + + return $"{simpleTypeName} {_parent.Metadata[TagHelperMetadata.Common.TypeName]}.{_metadata[TagHelperMetadata.Common.PropertyName]}"; + } + + return _name; + } + + private IEnumerable Validate() + { + // data-* attributes are explicitly not implemented by user agents and are not intended for use on + // the server; therefore it's invalid for TagHelpers to bind to them. + const string DataDashPrefix = "data-"; + + if (string.IsNullOrWhiteSpace(_name)) + { + if (_indexerNamePrefix == null) + { + var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributeNullOrWhitespace( + _parent.GetDisplayName(), + GetDisplayName()); + + yield return diagnostic; + } + } + else + { + if (_name.StartsWith(DataDashPrefix, StringComparison.OrdinalIgnoreCase)) + { + var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributeNameStartsWith( + _parent.GetDisplayName(), + GetDisplayName(), + _name); + + yield return diagnostic; + } + + foreach (var character in _name) + { + if (char.IsWhiteSpace(character) || HtmlConventions.InvalidNonWhitespaceHtmlCharacters.Contains(character)) + { + var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributeName( + _parent.GetDisplayName(), + GetDisplayName(), + _name, + character); + + yield return diagnostic; + } + } + } + + if (_indexerNamePrefix != null) + { + if (_indexerNamePrefix.StartsWith(DataDashPrefix, StringComparison.OrdinalIgnoreCase)) + { + var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributePrefixStartsWith( + _parent.GetDisplayName(), + GetDisplayName(), + _indexerNamePrefix); + + yield return diagnostic; + } + else if (_indexerNamePrefix.Length > 0 && string.IsNullOrWhiteSpace(_indexerNamePrefix)) + { + var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributeNullOrWhitespace( + _parent.GetDisplayName(), + GetDisplayName()); + + yield return diagnostic; + } + else + { + foreach (var character in _indexerNamePrefix) + { + if (char.IsWhiteSpace(character) || HtmlConventions.InvalidNonWhitespaceHtmlCharacters.Contains(character)) + { + var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributePrefix( + _parent.GetDisplayName(), + GetDisplayName(), + _indexerNamePrefix, + character); + + yield return diagnostic; + } + } + } + } + } + + private void EnsureDiagnostics() + { + if (_diagnostics == null) + { + _diagnostics = new HashSet(); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorTagHelperBinderPhase.cs b/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorTagHelperBinderPhase.cs index f3892516ee..41c4385d41 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorTagHelperBinderPhase.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorTagHelperBinderPhase.cs @@ -262,14 +262,6 @@ namespace Microsoft.AspNetCore.Razor.Language return false; } - if (!descriptor.IsDefaultKind()) - { - // We only understand default TagHelperDescriptors. - return false; - } - - var descriptorTypeName = descriptor.GetTypeName(); - if (lookupInfo.TypePattern.EndsWith("*", StringComparison.Ordinal)) { if (lookupInfo.TypePattern.Length == 1) @@ -280,10 +272,10 @@ namespace Microsoft.AspNetCore.Razor.Language var lookupTypeName = lookupInfo.TypePattern.Substring(0, lookupInfo.TypePattern.Length - 1); - return descriptorTypeName.StartsWith(lookupTypeName, StringComparison.Ordinal); + return descriptor.Name.StartsWith(lookupTypeName, StringComparison.Ordinal); } - return string.Equals(descriptorTypeName, lookupInfo.TypePattern, StringComparison.Ordinal); + return string.Equals(descriptor.Name, lookupInfo.TypePattern, StringComparison.Ordinal); } private static int GetErrorLength(string directiveText) diff --git a/src/Microsoft.AspNetCore.Razor.Language/DefaultRequiredAttributeDescriptor.cs b/src/Microsoft.AspNetCore.Razor.Language/DefaultRequiredAttributeDescriptor.cs new file mode 100644 index 0000000000..8802abcf7a --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Language/DefaultRequiredAttributeDescriptor.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. + +namespace Microsoft.AspNetCore.Razor.Language +{ + internal class DefaultRequiredAttributeDescriptor : RequiredAttributeDescriptor + { + public DefaultRequiredAttributeDescriptor( + string name, + NameComparisonMode nameComparison, + string value, + ValueComparisonMode valueComparison, + string displayName, + RazorDiagnostic[] diagnostics) + { + Name = name; + NameComparison = nameComparison; + Value = value; + ValueComparison = valueComparison; + DisplayName = displayName; + Diagnostics = diagnostics; + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Language/DefaultRequiredAttributeDescriptorBuilder.cs b/src/Microsoft.AspNetCore.Razor.Language/DefaultRequiredAttributeDescriptorBuilder.cs new file mode 100644 index 0000000000..2620051e60 --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Language/DefaultRequiredAttributeDescriptorBuilder.cs @@ -0,0 +1,105 @@ +// 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 DefaultRequiredAttributeDescriptorBuilder : RequiredAttributeDescriptorBuilder + { + private string _name; + private RequiredAttributeDescriptor.NameComparisonMode _nameComparison; + private string _value; + private RequiredAttributeDescriptor.ValueComparisonMode _valueComparison; + private HashSet _diagnostics; + + public override RequiredAttributeDescriptorBuilder Name(string name) + { + _name = name; + + return this; + } + + public override RequiredAttributeDescriptorBuilder NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode nameComparison) + { + _nameComparison = nameComparison; + + return this; + } + + public override RequiredAttributeDescriptorBuilder Value(string value) + { + _value = value; + + return this; + } + + public override RequiredAttributeDescriptorBuilder ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode valueComparison) + { + _valueComparison = valueComparison; + + return this; + } + + public override RequiredAttributeDescriptorBuilder AddDiagnostic(RazorDiagnostic diagnostic) + { + EnsureDiagnostics(); + _diagnostics.Add(diagnostic); + + return this; + } + + public RequiredAttributeDescriptor Build() + { + var validationDiagnostics = Validate(); + var diagnostics = new HashSet(validationDiagnostics); + if (_diagnostics != null) + { + diagnostics.UnionWith(_diagnostics); + } + + var displayName = _nameComparison == RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch ? string.Concat(_name, "...") : _name; + var rule = new DefaultRequiredAttributeDescriptor( + _name, + _nameComparison, + _value, + _valueComparison, + displayName, + diagnostics?.ToArray() ?? Array.Empty()); + + return rule; + } + + private IEnumerable Validate() + { + if (string.IsNullOrWhiteSpace(_name)) + { + var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedAttributeNameNullOrWhitespace(); + + yield return diagnostic; + } + else + { + foreach (var character in _name) + { + if (char.IsWhiteSpace(character) || HtmlConventions.InvalidNonWhitespaceHtmlCharacters.Contains(character)) + { + var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedAttributeName(_name, character); + + yield return diagnostic; + } + } + } + } + + private void EnsureDiagnostics() + { + if (_diagnostics == null) + { + _diagnostics = new HashSet(); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Language/DefaultTagHelperDescriptor.cs b/src/Microsoft.AspNetCore.Razor.Language/DefaultTagHelperDescriptor.cs new file mode 100644 index 0000000000..c9e3cd55eb --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Language/DefaultTagHelperDescriptor.cs @@ -0,0 +1,36 @@ +// 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 DefaultTagHelperDescriptor : TagHelperDescriptor + { + public DefaultTagHelperDescriptor( + string kind, + string name, + string assemblyName, + string displayName, + string documentation, + string tagOutputHint, + TagMatchingRuleDescriptor[] tagMatchingRules, + BoundAttributeDescriptor[] attributeDescriptors, + string[] allowedChildTags, + Dictionary metadata, + RazorDiagnostic[] diagnostics) + : base(kind) + { + Name = name; + AssemblyName = assemblyName; + DisplayName = displayName; + Documentation = documentation; + TagOutputHint = tagOutputHint; + TagMatchingRules = tagMatchingRules; + BoundAttributes = attributeDescriptors; + AllowedChildTags = allowedChildTags; + Diagnostics = diagnostics; + Metadata = metadata; + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Language/DefaultTagHelperDescriptorBuilder.cs b/src/Microsoft.AspNetCore.Razor.Language/DefaultTagHelperDescriptorBuilder.cs new file mode 100644 index 0000000000..4ae93c528d --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Language/DefaultTagHelperDescriptorBuilder.cs @@ -0,0 +1,258 @@ +// 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 DefaultTagHelperDescriptorBuilder : TagHelperDescriptorBuilder + { + // Required values + private readonly string _kind; + private readonly string _name; + private readonly string _assemblyName; + private readonly Dictionary _metadata; + + private string _displayName; + private string _documentation; + private string _tagOutputHint; + private HashSet _allowedChildTags; + private List _attributeBuilders; + private List _tagMatchingRuleBuilders; + private HashSet _diagnostics; + + public DefaultTagHelperDescriptorBuilder(string kind, string name, string assemblyName) + { + _kind = kind; + _name = name; + _assemblyName = assemblyName; + + _metadata = new Dictionary(StringComparer.Ordinal); + } + + public IDictionary Metadata => _metadata; + + public override TagHelperDescriptorBuilder BindAttribute(Action configure) + { + if (configure == null) + { + throw new ArgumentNullException(nameof(configure)); + } + + EnsureAttributeBuilders(); + + var builder = new DefaultBoundAttributeDescriptorBuilder(this, _kind); + configure(builder); + _attributeBuilders.Add(builder); + return this; + } + + public override TagHelperDescriptorBuilder TagMatchingRule(Action configure) + { + if (configure == null) + { + throw new ArgumentNullException(nameof(configure)); + } + + EnsureTagMatchingRuleBuilders(); + + var builder = new DefaultTagMatchingRuleDescriptorBuilder(); + configure(builder); + _tagMatchingRuleBuilders.Add(builder); + + return this; + } + + public override TagHelperDescriptorBuilder AllowChildTag(string allowedChild) + { + EnsureAllowedChildTags(); + _allowedChildTags.Add(allowedChild); + + return this; + } + + public override TagHelperDescriptorBuilder TagOutputHint(string hint) + { + _tagOutputHint = hint; + + return this; + } + + public override TagHelperDescriptorBuilder Documentation(string documentation) + { + _documentation = documentation; + + return this; + } + + public override TagHelperDescriptorBuilder AddMetadata(string key, string value) + { + _metadata[key] = value; + + return this; + } + + public override TagHelperDescriptorBuilder AddDiagnostic(RazorDiagnostic diagnostic) + { + EnsureDiagnostics(); + _diagnostics.Add(diagnostic); + + return this; + } + + public override TagHelperDescriptorBuilder DisplayName(string displayName) + { + if (displayName == null) + { + throw new ArgumentNullException(nameof(displayName)); + } + + _displayName = displayName; + + return this; + } + + public override TagHelperDescriptorBuilder TypeName(string typeName) + { + if (typeName == null) + { + throw new ArgumentNullException(nameof(typeName)); + } + + _metadata[TagHelperMetadata.Common.TypeName] = typeName; + return this; + } + + public override TagHelperDescriptor Build() + { + var validationDiagnostics = Validate(); + var diagnostics = new HashSet(validationDiagnostics); + if (_diagnostics != null) + { + diagnostics.UnionWith(_diagnostics); + } + + var tagMatchingRules = Array.Empty(); + if (_tagMatchingRuleBuilders != null) + { + var tagMatchingRuleSet = new HashSet(TagMatchingRuleDescriptorComparer.Default); + for (var i = 0; i < _tagMatchingRuleBuilders.Count; i++) + { + tagMatchingRuleSet.Add(_tagMatchingRuleBuilders[i].Build()); + } + + tagMatchingRules = tagMatchingRuleSet.ToArray(); + } + + var attributes = Array.Empty(); + if (_attributeBuilders != null) + { + var attributeSet = new HashSet(BoundAttributeDescriptorComparer.Default); + for (var i = 0; i < _attributeBuilders.Count; i++) + { + attributeSet.Add(_attributeBuilders[i].Build()); + } + + attributes = attributeSet.ToArray(); + } + + var descriptor = new DefaultTagHelperDescriptor( + _kind, + _name, + _assemblyName, + GetDisplayName(), + _documentation, + _tagOutputHint, + tagMatchingRules, + attributes, + _allowedChildTags?.ToArray() ?? Array.Empty(), + new Dictionary(_metadata), + diagnostics.ToArray()); + + return descriptor; + } + + public override void Reset() + { + _documentation = null; + _tagOutputHint = null; + _allowedChildTags?.Clear(); + _attributeBuilders?.Clear(); + _tagMatchingRuleBuilders?.Clear(); + _metadata.Clear(); + _diagnostics?.Clear(); + } + + public string GetDisplayName() + { + if (_displayName != null) + { + return _displayName; + } + + return _metadata.ContainsKey(TagHelperMetadata.Common.TypeName) ? _metadata[TagHelperMetadata.Common.TypeName] : _name; + } + + private IEnumerable Validate() + { + if (_allowedChildTags != null) + { + foreach (var name in _allowedChildTags) + { + if (string.IsNullOrWhiteSpace(name)) + { + var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidRestrictedChildNullOrWhitespace(GetDisplayName()); + + yield return diagnostic; + } + else if (name != TagHelperMatchingConventions.ElementCatchAllName) + { + foreach (var character in name) + { + if (char.IsWhiteSpace(character) || HtmlConventions.InvalidNonWhitespaceHtmlCharacters.Contains(character)) + { + var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidRestrictedChild(GetDisplayName(), name, character); + + yield return diagnostic; + } + } + } + } + } + } + + private void EnsureAttributeBuilders() + { + if (_attributeBuilders == null) + { + _attributeBuilders = new List(); + } + } + + private void EnsureTagMatchingRuleBuilders() + { + if (_tagMatchingRuleBuilders == null) + { + _tagMatchingRuleBuilders = new List(); + } + } + + private void EnsureAllowedChildTags() + { + if (_allowedChildTags == null) + { + _allowedChildTags = new HashSet(StringComparer.OrdinalIgnoreCase); + } + } + + private void EnsureDiagnostics() + { + if (_diagnostics == null) + { + _diagnostics = new HashSet(); + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Language/DefaultTagMatchingRuleDescriptor.cs b/src/Microsoft.AspNetCore.Razor.Language/DefaultTagMatchingRuleDescriptor.cs new file mode 100644 index 0000000000..78595a9165 --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Language/DefaultTagMatchingRuleDescriptor.cs @@ -0,0 +1,22 @@ +// 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. + +namespace Microsoft.AspNetCore.Razor.Language +{ + internal class DefaultTagMatchingRuleDescriptor : TagMatchingRuleDescriptor + { + public DefaultTagMatchingRuleDescriptor( + string tagName, + string parentTag, + TagStructure tagStructure, + RequiredAttributeDescriptor[] attributes, + RazorDiagnostic[] diagnostics) + { + TagName = tagName; + ParentTag = parentTag; + TagStructure = tagStructure; + Attributes = attributes; + Diagnostics = diagnostics; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Razor.Language/TagMatchingRuleBuilder.cs b/src/Microsoft.AspNetCore.Razor.Language/DefaultTagMatchingRuleDescriptorBuilder.cs similarity index 56% rename from src/Microsoft.AspNetCore.Razor.Language/TagMatchingRuleBuilder.cs rename to src/Microsoft.AspNetCore.Razor.Language/DefaultTagMatchingRuleDescriptorBuilder.cs index 6f576f44b6..3e1a659bcf 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/TagMatchingRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/DefaultTagMatchingRuleDescriptorBuilder.cs @@ -8,74 +8,56 @@ using Microsoft.AspNetCore.Razor.Language.Legacy; namespace Microsoft.AspNetCore.Razor.Language { - public sealed class TagMatchingRuleBuilder + internal class DefaultTagMatchingRuleDescriptorBuilder : TagMatchingRuleDescriptorBuilder { private string _tagName; private string _parentTag; private TagStructure _tagStructure; - private HashSet _requiredAttributeDescriptors; + private List _requiredAttributeBuilders; private HashSet _diagnostics; - private TagMatchingRuleBuilder() + internal DefaultTagMatchingRuleDescriptorBuilder() { } - public static TagMatchingRuleBuilder Create() - { - return new TagMatchingRuleBuilder(); - } - - public TagMatchingRuleBuilder RequireTagName(string tagName) + public override TagMatchingRuleDescriptorBuilder RequireTagName(string tagName) { _tagName = tagName; return this; } - public TagMatchingRuleBuilder RequireParentTag(string parentTag) + public override TagMatchingRuleDescriptorBuilder RequireParentTag(string parentTag) { _parentTag = parentTag; return this; } - public TagMatchingRuleBuilder RequireTagStructure(TagStructure tagStructure) + public override TagMatchingRuleDescriptorBuilder RequireTagStructure(TagStructure tagStructure) { _tagStructure = tagStructure; return this; } - public TagMatchingRuleBuilder RequireAttribute(RequiredAttributeDescriptor requiredAttributeDescriptor) - { - if (requiredAttributeDescriptor == null) - { - throw new ArgumentNullException(nameof(requiredAttributeDescriptor)); - } - - EnsureRequiredAttributeDescriptors(); - _requiredAttributeDescriptors.Add(requiredAttributeDescriptor); - - return this; - } - - public TagMatchingRuleBuilder RequireAttribute(Action configure) + public override TagMatchingRuleDescriptorBuilder RequireAttribute(Action configure) { if (configure == null) { throw new ArgumentNullException(nameof(configure)); } - var builder = RequiredAttributeDescriptorBuilder.Create(); + EnsureRequiredAttributeBuilders(); + var builder = new DefaultRequiredAttributeDescriptorBuilder(); configure(builder); + _requiredAttributeBuilders.Add(builder); - var requiredAttributeDescriptor = builder.Build(); - - return RequireAttribute(requiredAttributeDescriptor); + return this; } - public TagMatchingRuleBuilder AddDiagnostic(RazorDiagnostic diagnostic) + public override TagMatchingRuleDescriptorBuilder AddDiagnostic(RazorDiagnostic diagnostic) { EnsureDiagnostics(); _diagnostics.Add(diagnostic); @@ -83,7 +65,7 @@ namespace Microsoft.AspNetCore.Razor.Language return this; } - public TagMatchingRule Build() + public TagMatchingRuleDescriptor Build() { var validationDiagnostics = Validate(); var diagnostics = new HashSet(validationDiagnostics); @@ -92,25 +74,28 @@ namespace Microsoft.AspNetCore.Razor.Language diagnostics.UnionWith(_diagnostics); } - var rule = new DefaultTagMatchingRule( + var requiredAttributes = Array.Empty(); + if (_requiredAttributeBuilders != null) + { + var requiredAttributeSet = new HashSet(RequiredAttributeDescriptorComparer.Default); + for (var i = 0; i < _requiredAttributeBuilders.Count; i++) + { + requiredAttributeSet.Add(_requiredAttributeBuilders[i].Build()); + } + + requiredAttributes = requiredAttributeSet.ToArray(); + } + + var rule = new DefaultTagMatchingRuleDescriptor( _tagName, _parentTag, _tagStructure, - _requiredAttributeDescriptors ?? Enumerable.Empty(), - diagnostics); + requiredAttributes, + diagnostics.ToArray()); return rule; } - public void Reset() - { - _tagName = null; - _parentTag = null; - _tagStructure = default(TagStructure); - _requiredAttributeDescriptors?.Clear(); - _diagnostics?.Clear(); - } - private IEnumerable Validate() { if (string.IsNullOrWhiteSpace(_tagName)) @@ -155,11 +140,11 @@ namespace Microsoft.AspNetCore.Razor.Language } } - private void EnsureRequiredAttributeDescriptors() + private void EnsureRequiredAttributeBuilders() { - if (_requiredAttributeDescriptors == null) + if (_requiredAttributeBuilders == null) { - _requiredAttributeDescriptors = new HashSet(RequiredAttributeDescriptorComparer.Default); + _requiredAttributeBuilders = new List(); } } @@ -170,22 +155,5 @@ namespace Microsoft.AspNetCore.Razor.Language _diagnostics = new HashSet(); } } - - private class DefaultTagMatchingRule : TagMatchingRule - { - public DefaultTagMatchingRule( - string tagName, - string parentTag, - TagStructure tagStructure, - IEnumerable requiredAttributeDescriptors, - IEnumerable diagnostics) - { - TagName = tagName; - ParentTag = parentTag; - TagStructure = tagStructure; - Attributes = new List(requiredAttributeDescriptors); - Diagnostics = new List(diagnostics); - } - } } } diff --git a/src/Microsoft.AspNetCore.Razor.Language/Legacy/TagHelperParseTreeRewriter.cs b/src/Microsoft.AspNetCore.Razor.Language/Legacy/TagHelperParseTreeRewriter.cs index 959980e326..f138573498 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Legacy/TagHelperParseTreeRewriter.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/Legacy/TagHelperParseTreeRewriter.cs @@ -273,14 +273,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy if (invalidRule != null) { - var typeName = descriptor.GetTypeName(); - // End tag TagHelper that states it shouldn't have an end tag. errorSink.OnError( SourceLocationTracker.Advance(tagBlock.Start, " string.Format(CultureInfo.CurrentCulture, GetString("FeatureDependencyMissing"), p0, p1, p2); /// - /// Invalid tag helper directive look up text '{0}'. The correct look up text format is: "typeName, assemblyName". + /// Invalid tag helper directive look up text '{0}'. The correct look up text format is: "name, assemblyName". /// internal static string InvalidTagHelperLookupText { @@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Razor.Language } /// - /// Invalid tag helper directive look up text '{0}'. The correct look up text format is: "typeName, assemblyName". + /// Invalid tag helper directive look up text '{0}'. The correct look up text format is: "name, assemblyName". /// internal static string FormatInvalidTagHelperLookupText(object p0) => string.Format(CultureInfo.CurrentCulture, GetString("InvalidTagHelperLookupText"), p0); @@ -193,186 +193,186 @@ namespace Microsoft.AspNetCore.Razor.Language => string.Format(CultureInfo.CurrentCulture, GetString("RazorTemplateEngine_ItemCouldNotBeFound"), p0); /// - /// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with name '{2}' because the name contains a '{3}' character. + /// Invalid tag helper bound property '{1}' on tag helper '{0}'. Tag helpers cannot bind to HTML attributes with name '{2}' because the name contains a '{3}' character. /// - internal static string InvalidBoundAttributeName + internal static string TagHelper_InvalidBoundAttributeName { - get => GetString("InvalidBoundAttributeName"); + get => GetString("TagHelper_InvalidBoundAttributeName"); } /// - /// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with name '{2}' because the name contains a '{3}' character. + /// Invalid tag helper bound property '{1}' on tag helper '{0}'. Tag helpers cannot bind to HTML attributes with name '{2}' because the name contains a '{3}' character. /// - internal static string FormatInvalidBoundAttributeName(object p0, object p1, object p2, object p3) - => string.Format(CultureInfo.CurrentCulture, GetString("InvalidBoundAttributeName"), p0, p1, p2, p3); + internal static string FormatTagHelper_InvalidBoundAttributeName(object p0, object p1, object p2, object p3) + => string.Format(CultureInfo.CurrentCulture, GetString("TagHelper_InvalidBoundAttributeName"), p0, p1, p2, p3); /// - /// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with name '{2}' because the name starts with '{3}'. + /// Invalid tag helper bound property '{1}' on tag helper '{0}'. Tag helpers cannot bind to HTML attributes with name '{2}' because the name starts with '{3}'. /// - internal static string InvalidBoundAttributeNameStartsWith + internal static string TagHelper_InvalidBoundAttributeNameStartsWith { - get => GetString("InvalidBoundAttributeNameStartsWith"); + get => GetString("TagHelper_InvalidBoundAttributeNameStartsWith"); } /// - /// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with name '{2}' because the name starts with '{3}'. + /// Invalid tag helper bound property '{1}' on tag helper '{0}'. Tag helpers cannot bind to HTML attributes with name '{2}' because the name starts with '{3}'. /// - internal static string FormatInvalidBoundAttributeNameStartsWith(object p0, object p1, object p2, object p3) - => string.Format(CultureInfo.CurrentCulture, GetString("InvalidBoundAttributeNameStartsWith"), p0, p1, p2, p3); + internal static string FormatTagHelper_InvalidBoundAttributeNameStartsWith(object p0, object p1, object p2, object p3) + => string.Format(CultureInfo.CurrentCulture, GetString("TagHelper_InvalidBoundAttributeNameStartsWith"), p0, p1, p2, p3); /// - /// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with a null or empty name. + /// Invalid tag helper bound property '{1}' on tag helper '{0}'. Tag helpers cannot bind to HTML attributes with a null or empty name. /// - internal static string InvalidBoundAttributeNullOrWhitespace + internal static string TagHelper_InvalidBoundAttributeNullOrWhitespace { - get => GetString("InvalidBoundAttributeNullOrWhitespace"); + get => GetString("TagHelper_InvalidBoundAttributeNullOrWhitespace"); } /// - /// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with a null or empty name. + /// Invalid tag helper bound property '{1}' on tag helper '{0}'. Tag helpers cannot bind to HTML attributes with a null or empty name. /// - internal static string FormatInvalidBoundAttributeNullOrWhitespace(object p0, object p1) - => string.Format(CultureInfo.CurrentCulture, GetString("InvalidBoundAttributeNullOrWhitespace"), p0, p1); + internal static string FormatTagHelper_InvalidBoundAttributeNullOrWhitespace(object p0, object p1) + => string.Format(CultureInfo.CurrentCulture, GetString("TagHelper_InvalidBoundAttributeNullOrWhitespace"), p0, p1); /// - /// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with prefix '{2}' because the prefix contains a '{3}' character. + /// Invalid tag helper bound property '{1}' on tag helper '{0}'. Tag helpers cannot bind to HTML attributes with prefix '{2}' because the prefix contains a '{3}' character. /// - internal static string InvalidBoundAttributePrefix + internal static string TagHelper_InvalidBoundAttributePrefix { - get => GetString("InvalidBoundAttributePrefix"); + get => GetString("TagHelper_InvalidBoundAttributePrefix"); } /// - /// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with prefix '{2}' because the prefix contains a '{3}' character. + /// Invalid tag helper bound property '{1}' on tag helper '{0}'. Tag helpers cannot bind to HTML attributes with prefix '{2}' because the prefix contains a '{3}' character. /// - internal static string FormatInvalidBoundAttributePrefix(object p0, object p1, object p2, object p3) - => string.Format(CultureInfo.CurrentCulture, GetString("InvalidBoundAttributePrefix"), p0, p1, p2, p3); + internal static string FormatTagHelper_InvalidBoundAttributePrefix(object p0, object p1, object p2, object p3) + => string.Format(CultureInfo.CurrentCulture, GetString("TagHelper_InvalidBoundAttributePrefix"), p0, p1, p2, p3); /// - /// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with prefix '{2}' because the prefix starts with '{3}'. + /// Invalid tag helper bound property '{1}' on tag helper '{0}'. Tag helpers cannot bind to HTML attributes with prefix '{2}' because the prefix starts with '{3}'. /// - internal static string InvalidBoundAttributePrefixStartsWith + internal static string TagHelper_InvalidBoundAttributePrefixStartsWith { - get => GetString("InvalidBoundAttributePrefixStartsWith"); + get => GetString("TagHelper_InvalidBoundAttributePrefixStartsWith"); } /// - /// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with prefix '{2}' because the prefix starts with '{3}'. + /// Invalid tag helper bound property '{1}' on tag helper '{0}'. Tag helpers cannot bind to HTML attributes with prefix '{2}' because the prefix starts with '{3}'. /// - internal static string FormatInvalidBoundAttributePrefixStartsWith(object p0, object p1, object p2, object p3) - => string.Format(CultureInfo.CurrentCulture, GetString("InvalidBoundAttributePrefixStartsWith"), p0, p1, p2, p3); + internal static string FormatTagHelper_InvalidBoundAttributePrefixStartsWith(object p0, object p1, object p2, object p3) + => string.Format(CultureInfo.CurrentCulture, GetString("TagHelper_InvalidBoundAttributePrefixStartsWith"), p0, p1, p2, p3); /// - /// Invalid restricted child '{0}' for tag helper '{1}'. Tag helpers cannot restrict child elements that contain a '{2}' character. + /// Invalid restricted child '{1}' for tag helper '{0}'. Tag helpers cannot restrict child elements that contain a '{2}' character. /// - internal static string InvalidRestrictedChild + internal static string TagHelper_InvalidRestrictedChild { - get => GetString("InvalidRestrictedChild"); + get => GetString("TagHelper_InvalidRestrictedChild"); } /// - /// Invalid restricted child '{0}' for tag helper '{1}'. Tag helpers cannot restrict child elements that contain a '{2}' character. + /// Invalid restricted child '{1}' for tag helper '{0}'. Tag helpers cannot restrict child elements that contain a '{2}' character. /// - internal static string FormatInvalidRestrictedChild(object p0, object p1, object p2) - => string.Format(CultureInfo.CurrentCulture, GetString("InvalidRestrictedChild"), p0, p1, p2); + internal static string FormatTagHelper_InvalidRestrictedChild(object p0, object p1, object p2) + => string.Format(CultureInfo.CurrentCulture, GetString("TagHelper_InvalidRestrictedChild"), p0, p1, p2); /// /// Invalid restricted child for tag helper '{0}'. Name cannot be null or whitespace. /// - internal static string InvalidRestrictedChildNullOrWhitespace + internal static string TagHelper_InvalidRestrictedChildNullOrWhitespace { - get => GetString("InvalidRestrictedChildNullOrWhitespace"); + get => GetString("TagHelper_InvalidRestrictedChildNullOrWhitespace"); } /// /// Invalid restricted child for tag helper '{0}'. Name cannot be null or whitespace. /// - internal static string FormatInvalidRestrictedChildNullOrWhitespace(object p0) - => string.Format(CultureInfo.CurrentCulture, GetString("InvalidRestrictedChildNullOrWhitespace"), p0); + internal static string FormatTagHelper_InvalidRestrictedChildNullOrWhitespace(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("TagHelper_InvalidRestrictedChildNullOrWhitespace"), p0); /// /// Tag helpers cannot target attribute name '{0}' because it contains a '{1}' character. /// - internal static string InvalidTargetedAttributeName + internal static string TagHelper_InvalidTargetedAttributeName { - get => GetString("InvalidTargetedAttributeName"); + get => GetString("TagHelper_InvalidTargetedAttributeName"); } /// /// Tag helpers cannot target attribute name '{0}' because it contains a '{1}' character. /// - internal static string FormatInvalidTargetedAttributeName(object p0, object p1) - => string.Format(CultureInfo.CurrentCulture, GetString("InvalidTargetedAttributeName"), p0, p1); + internal static string FormatTagHelper_InvalidTargetedAttributeName(object p0, object p1) + => string.Format(CultureInfo.CurrentCulture, GetString("TagHelper_InvalidTargetedAttributeName"), p0, p1); /// /// Targeted attribute name cannot be null or whitespace. /// - internal static string InvalidTargetedAttributeNameNullOrWhitespace + internal static string TagHelper_InvalidTargetedAttributeNameNullOrWhitespace { - get => GetString("InvalidTargetedAttributeNameNullOrWhitespace"); + get => GetString("TagHelper_InvalidTargetedAttributeNameNullOrWhitespace"); } /// /// Targeted attribute name cannot be null or whitespace. /// - internal static string FormatInvalidTargetedAttributeNameNullOrWhitespace() - => GetString("InvalidTargetedAttributeNameNullOrWhitespace"); + internal static string FormatTagHelper_InvalidTargetedAttributeNameNullOrWhitespace() + => GetString("TagHelper_InvalidTargetedAttributeNameNullOrWhitespace"); /// /// Tag helpers cannot target parent tag name '{0}' because it contains a '{1}' character. /// - internal static string InvalidTargetedParentTagName + internal static string TagHelper_InvalidTargetedParentTagName { - get => GetString("InvalidTargetedParentTagName"); + get => GetString("TagHelper_InvalidTargetedParentTagName"); } /// /// Tag helpers cannot target parent tag name '{0}' because it contains a '{1}' character. /// - internal static string FormatInvalidTargetedParentTagName(object p0, object p1) - => string.Format(CultureInfo.CurrentCulture, GetString("InvalidTargetedParentTagName"), p0, p1); + internal static string FormatTagHelper_InvalidTargetedParentTagName(object p0, object p1) + => string.Format(CultureInfo.CurrentCulture, GetString("TagHelper_InvalidTargetedParentTagName"), p0, p1); /// /// Targeted parent tag name cannot be null or whitespace. /// - internal static string InvalidTargetedParentTagNameNullOrWhitespace + internal static string TagHelper_InvalidTargetedParentTagNameNullOrWhitespace { - get => GetString("InvalidTargetedParentTagNameNullOrWhitespace"); + get => GetString("TagHelper_InvalidTargetedParentTagNameNullOrWhitespace"); } /// /// Targeted parent tag name cannot be null or whitespace. /// - internal static string FormatInvalidTargetedParentTagNameNullOrWhitespace() - => GetString("InvalidTargetedParentTagNameNullOrWhitespace"); + internal static string FormatTagHelper_InvalidTargetedParentTagNameNullOrWhitespace() + => GetString("TagHelper_InvalidTargetedParentTagNameNullOrWhitespace"); /// /// Tag helpers cannot target tag name '{0}' because it contains a '{1}' character. /// - internal static string InvalidTargetedTagName + internal static string TagHelper_InvalidTargetedTagName { - get => GetString("InvalidTargetedTagName"); + get => GetString("TagHelper_InvalidTargetedTagName"); } /// /// Tag helpers cannot target tag name '{0}' because it contains a '{1}' character. /// - internal static string FormatInvalidTargetedTagName(object p0, object p1) - => string.Format(CultureInfo.CurrentCulture, GetString("InvalidTargetedTagName"), p0, p1); + internal static string FormatTagHelper_InvalidTargetedTagName(object p0, object p1) + => string.Format(CultureInfo.CurrentCulture, GetString("TagHelper_InvalidTargetedTagName"), p0, p1); /// /// Targeted tag name cannot be null or whitespace. /// - internal static string InvalidTargetedTagNameNullOrWhitespace + internal static string TagHelper_InvalidTargetedTagNameNullOrWhitespace { - get => GetString("InvalidTargetedTagNameNullOrWhitespace"); + get => GetString("TagHelper_InvalidTargetedTagNameNullOrWhitespace"); } /// /// Targeted tag name cannot be null or whitespace. /// - internal static string FormatInvalidTargetedTagNameNullOrWhitespace() - => GetString("InvalidTargetedTagNameNullOrWhitespace"); + internal static string FormatTagHelper_InvalidTargetedTagNameNullOrWhitespace() + => GetString("TagHelper_InvalidTargetedTagNameNullOrWhitespace"); /// /// The node '{0}' is not the owner of change '{1}'. diff --git a/src/Microsoft.AspNetCore.Razor.Language/RazorDiagnosticFactory.cs b/src/Microsoft.AspNetCore.Razor.Language/RazorDiagnosticFactory.cs index 80e5d6043c..8d8e7872f8 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/RazorDiagnosticFactory.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/RazorDiagnosticFactory.cs @@ -61,144 +61,144 @@ namespace Microsoft.AspNetCore.Razor.Language // TagHelper Errors ID Offset = 3000 - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidRestrictedChildNullOrWhitespace = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidRestrictedChildNullOrWhitespace = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3000", - () => Resources.InvalidRestrictedChildNullOrWhitespace, + () => Resources.TagHelper_InvalidRestrictedChildNullOrWhitespace, RazorDiagnosticSeverity.Error); - public static RazorDiagnostic CreateTagHelper_InvalidRestrictedChildNullOrWhitespace(string tagHelperType) + public static RazorDiagnostic CreateTagHelper_InvalidRestrictedChildNullOrWhitespace(string tagHelperDisplayName) { var diagnostic = RazorDiagnostic.Create( TagHelper_InvalidRestrictedChildNullOrWhitespace, new SourceSpan(SourceLocation.Undefined, contentLength: 0), - tagHelperType); + tagHelperDisplayName); return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidRestrictedChild = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidRestrictedChild = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3001", - () => Resources.InvalidRestrictedChild, + () => Resources.TagHelper_InvalidRestrictedChild, RazorDiagnosticSeverity.Error); - public static RazorDiagnostic CreateTagHelper_InvalidRestrictedChild(string restrictedChild, string tagHelperType, char invalidCharacter) + public static RazorDiagnostic CreateTagHelper_InvalidRestrictedChild(string tagHelperDisplayName, string restrictedChild, char invalidCharacter) { var diagnostic = RazorDiagnostic.Create( TagHelper_InvalidRestrictedChild, new SourceSpan(SourceLocation.Undefined, contentLength: 0), + tagHelperDisplayName, restrictedChild, - tagHelperType, invalidCharacter); return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidBoundAttributeNullOrWhitespace = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidBoundAttributeNullOrWhitespace = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3002", - () => Resources.InvalidBoundAttributeNullOrWhitespace, + () => Resources.TagHelper_InvalidBoundAttributeNullOrWhitespace, RazorDiagnosticSeverity.Error); - public static RazorDiagnostic CreateTagHelper_InvalidBoundAttributeNullOrWhitespace(string containingTypeName, string propertyName) + public static RazorDiagnostic CreateTagHelper_InvalidBoundAttributeNullOrWhitespace(string tagHelperDisplayName, string propertyDisplayName) { var diagnostic = RazorDiagnostic.Create( TagHelper_InvalidBoundAttributeNullOrWhitespace, new SourceSpan(SourceLocation.Undefined, contentLength: 0), - containingTypeName, - propertyName); + tagHelperDisplayName, + propertyDisplayName); return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidBoundAttributeName = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidBoundAttributeName = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3003", - () => Resources.InvalidBoundAttributeName, + () => Resources.TagHelper_InvalidBoundAttributeName, RazorDiagnosticSeverity.Error); public static RazorDiagnostic CreateTagHelper_InvalidBoundAttributeName( - string containingTypeName, - string propertyName, + string tagHelperDisplayName, + string propertyDisplayName, string invalidName, char invalidCharacter) { var diagnostic = RazorDiagnostic.Create( TagHelper_InvalidBoundAttributeName, new SourceSpan(SourceLocation.Undefined, contentLength: 0), - containingTypeName, - propertyName, + tagHelperDisplayName, + propertyDisplayName, invalidName, invalidCharacter); return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidBoundAttributeNameStartsWith = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidBoundAttributeNameStartsWith = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3004", - () => Resources.InvalidBoundAttributeNameStartsWith, + () => Resources.TagHelper_InvalidBoundAttributeNameStartsWith, RazorDiagnosticSeverity.Error); public static RazorDiagnostic CreateTagHelper_InvalidBoundAttributeNameStartsWith( - string containingTypeName, - string propertyName, + string tagHelperDisplayName, + string propertyDisplayName, string invalidName) { var diagnostic = RazorDiagnostic.Create( TagHelper_InvalidBoundAttributeNameStartsWith, new SourceSpan(SourceLocation.Undefined, contentLength: 0), - containingTypeName, - propertyName, + tagHelperDisplayName, + propertyDisplayName, invalidName, "data-"); return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidBoundAttributePrefix = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidBoundAttributePrefix = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3005", - () => Resources.InvalidBoundAttributePrefix, + () => Resources.TagHelper_InvalidBoundAttributePrefix, RazorDiagnosticSeverity.Error); public static RazorDiagnostic CreateTagHelper_InvalidBoundAttributePrefix( - string containingTypeName, - string propertyName, + string tagHelperDisplayName, + string propertyDisplayName, string invalidName, char invalidCharacter) { var diagnostic = RazorDiagnostic.Create( TagHelper_InvalidBoundAttributePrefix, new SourceSpan(SourceLocation.Undefined, contentLength: 0), - containingTypeName, - propertyName, + tagHelperDisplayName, + propertyDisplayName, invalidName, invalidCharacter); return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidBoundAttributePrefixStartsWith = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidBoundAttributePrefixStartsWith = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3006", - () => Resources.InvalidBoundAttributePrefixStartsWith, + () => Resources.TagHelper_InvalidBoundAttributePrefixStartsWith, RazorDiagnosticSeverity.Error); public static RazorDiagnostic CreateTagHelper_InvalidBoundAttributePrefixStartsWith( - string containingTypeName, - string propertyName, + string tagHelperDisplayName, + string propertyDisplayName, string invalidName) { var diagnostic = RazorDiagnostic.Create( TagHelper_InvalidBoundAttributePrefixStartsWith, new SourceSpan(SourceLocation.Undefined, contentLength: 0), - containingTypeName, - propertyName, + tagHelperDisplayName, + propertyDisplayName, invalidName, "data-"); return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidTargetedTagNameNullOrWhitespace = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidTargetedTagNameNullOrWhitespace = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3007", - () => Resources.InvalidTargetedTagNameNullOrWhitespace, + () => Resources.TagHelper_InvalidTargetedTagNameNullOrWhitespace, RazorDiagnosticSeverity.Error); public static RazorDiagnostic CreateTagHelper_InvalidTargetedTagNameNullOrWhitespace() { @@ -209,10 +209,10 @@ namespace Microsoft.AspNetCore.Razor.Language return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidTargetedTagName = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidTargetedTagName = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3008", - () => Resources.InvalidTargetedTagName, + () => Resources.TagHelper_InvalidTargetedTagName, RazorDiagnosticSeverity.Error); public static RazorDiagnostic CreateTagHelper_InvalidTargetedTagName(string invalidTagName, char invalidCharacter) { @@ -225,10 +225,10 @@ namespace Microsoft.AspNetCore.Razor.Language return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidTargetedParentTagNameNullOrWhitespace = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidTargetedParentTagNameNullOrWhitespace = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3009", - () => Resources.InvalidTargetedParentTagNameNullOrWhitespace, + () => Resources.TagHelper_InvalidTargetedParentTagNameNullOrWhitespace, RazorDiagnosticSeverity.Error); public static RazorDiagnostic CreateTagHelper_InvalidTargetedParentTagNameNullOrWhitespace() { @@ -239,10 +239,10 @@ namespace Microsoft.AspNetCore.Razor.Language return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidTargetedParentTagName = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidTargetedParentTagName = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3010", - () => Resources.InvalidTargetedParentTagName, + () => Resources.TagHelper_InvalidTargetedParentTagName, RazorDiagnosticSeverity.Error); public static RazorDiagnostic CreateTagHelper_InvalidTargetedParentTagName(string invalidTagName, char invalidCharacter) { @@ -255,10 +255,10 @@ namespace Microsoft.AspNetCore.Razor.Language return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidTargetedAttributeNameNullOrWhitespace = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidTargetedAttributeNameNullOrWhitespace = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3009", - () => Resources.InvalidTargetedAttributeNameNullOrWhitespace, + () => Resources.TagHelper_InvalidTargetedAttributeNameNullOrWhitespace, RazorDiagnosticSeverity.Error); public static RazorDiagnostic CreateTagHelper_InvalidTargetedAttributeNameNullOrWhitespace() { @@ -269,10 +269,10 @@ namespace Microsoft.AspNetCore.Razor.Language return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidTargetedAttributeName = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidTargetedAttributeName = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3010", - () => Resources.InvalidTargetedAttributeName, + () => Resources.TagHelper_InvalidTargetedAttributeName, RazorDiagnosticSeverity.Error); public static RazorDiagnostic CreateTagHelper_InvalidTargetedAttributeName(string invalidAttributeName, char invalidCharacter) { diff --git a/src/Microsoft.AspNetCore.Razor.Language/RequiredAttributeDescriptor.cs b/src/Microsoft.AspNetCore.Razor.Language/RequiredAttributeDescriptor.cs index 5fa519f6a7..6da95bfd4d 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/RequiredAttributeDescriptor.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/RequiredAttributeDescriptor.cs @@ -8,6 +8,7 @@ using System.Linq; namespace Microsoft.AspNetCore.Razor.Language { + [DebuggerDisplay("{DisplayName,nq}")] public abstract class RequiredAttributeDescriptor { public string Name { get; protected set; } diff --git a/src/Microsoft.AspNetCore.Razor.Language/RequiredAttributeDescriptorBuilder.cs b/src/Microsoft.AspNetCore.Razor.Language/RequiredAttributeDescriptorBuilder.cs index 098de7cea4..77f91eacff 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/RequiredAttributeDescriptorBuilder.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/RequiredAttributeDescriptorBuilder.cs @@ -1,142 +1,18 @@ // 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 sealed class RequiredAttributeDescriptorBuilder + public abstract class RequiredAttributeDescriptorBuilder { - private string _name; - private RequiredAttributeDescriptor.NameComparisonMode _nameComparison; - private string _value; - private RequiredAttributeDescriptor.ValueComparisonMode _valueComparison; - private HashSet _diagnostics; + public abstract RequiredAttributeDescriptorBuilder Name(string name); - private RequiredAttributeDescriptorBuilder() - { - } + public abstract RequiredAttributeDescriptorBuilder NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode nameComparison); - public static RequiredAttributeDescriptorBuilder Create() - { - return new RequiredAttributeDescriptorBuilder(); - } + public abstract RequiredAttributeDescriptorBuilder Value(string value); - public RequiredAttributeDescriptorBuilder Name(string name) - { - _name = name; + public abstract RequiredAttributeDescriptorBuilder ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode valueComparison); - return this; - } - - public RequiredAttributeDescriptorBuilder NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode nameComparison) - { - _nameComparison = nameComparison; - - return this; - } - - public RequiredAttributeDescriptorBuilder Value(string value) - { - _value = value; - - return this; - } - - public RequiredAttributeDescriptorBuilder ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode valueComparison) - { - _valueComparison = valueComparison; - - return this; - } - - public RequiredAttributeDescriptorBuilder AddDiagnostic(RazorDiagnostic diagnostic) - { - EnsureDiagnostics(); - _diagnostics.Add(diagnostic); - - return this; - } - - public RequiredAttributeDescriptor Build() - { - var validationDiagnostics = Validate(); - var diagnostics = new HashSet(validationDiagnostics); - if (_diagnostics != null) - { - diagnostics.UnionWith(_diagnostics); - } - - var displayName = _nameComparison == RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch ? string.Concat(_name, "...") : _name; - var rule = new DefaultTagHelperRequiredAttributeDescriptor( - _name, - _nameComparison, - _value, - _valueComparison, - displayName, - diagnostics); - - return rule; - } - - public void Reset() - { - _name = null; - _value = null; - _nameComparison = default(RequiredAttributeDescriptor.NameComparisonMode); - _valueComparison = default(RequiredAttributeDescriptor.ValueComparisonMode); - _diagnostics?.Clear(); - } - - private IEnumerable Validate() - { - if (string.IsNullOrWhiteSpace(_name)) - { - var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedAttributeNameNullOrWhitespace(); - - yield return diagnostic; - } - else - { - foreach (var character in _name) - { - if (char.IsWhiteSpace(character) || HtmlConventions.InvalidNonWhitespaceHtmlCharacters.Contains(character)) - { - var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedAttributeName(_name, character); - - yield return diagnostic; - } - } - } - } - - private void EnsureDiagnostics() - { - if (_diagnostics == null) - { - _diagnostics = new HashSet(); - } - } - - private class DefaultTagHelperRequiredAttributeDescriptor : RequiredAttributeDescriptor - { - public DefaultTagHelperRequiredAttributeDescriptor( - string name, - NameComparisonMode nameComparison, - string value, - ValueComparisonMode valueComparison, - string displayName, - IEnumerable diagnostics) - { - Name = name; - NameComparison = nameComparison; - Value = value; - ValueComparison = valueComparison; - DisplayName = displayName; - Diagnostics = new List(diagnostics); - } - } + public abstract RequiredAttributeDescriptorBuilder AddDiagnostic(RazorDiagnostic diagnostic); } } diff --git a/src/Microsoft.AspNetCore.Razor.Language/Resources.resx b/src/Microsoft.AspNetCore.Razor.Language/Resources.resx index b0b16e933f..6e07cf8e3d 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/Resources.resx +++ b/src/Microsoft.AspNetCore.Razor.Language/Resources.resx @@ -124,7 +124,7 @@ The '{0}' feature requires a '{1}' provided by the '{2}'. - Invalid tag helper directive look up text '{0}'. The correct look up text format is: "typeName, assemblyName". + Invalid tag helper directive look up text '{0}'. The correct look up text format is: "name, assemblyName". Invalid tag helper directive '{0}' value. '{1}' is not allowed in prefix '{2}'. @@ -156,43 +156,43 @@ The item '{0}' could not be found. - - Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with name '{2}' because the name contains a '{3}' character. + + Invalid tag helper bound property '{1}' on tag helper '{0}'. Tag helpers cannot bind to HTML attributes with name '{2}' because the name contains a '{3}' character. - - Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with name '{2}' because the name starts with '{3}'. + + Invalid tag helper bound property '{1}' on tag helper '{0}'. Tag helpers cannot bind to HTML attributes with name '{2}' because the name starts with '{3}'. - - Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with a null or empty name. + + Invalid tag helper bound property '{1}' on tag helper '{0}'. Tag helpers cannot bind to HTML attributes with a null or empty name. - - Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with prefix '{2}' because the prefix contains a '{3}' character. + + Invalid tag helper bound property '{1}' on tag helper '{0}'. Tag helpers cannot bind to HTML attributes with prefix '{2}' because the prefix contains a '{3}' character. - - Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with prefix '{2}' because the prefix starts with '{3}'. + + Invalid tag helper bound property '{1}' on tag helper '{0}'. Tag helpers cannot bind to HTML attributes with prefix '{2}' because the prefix starts with '{3}'. - - Invalid restricted child '{0}' for tag helper '{1}'. Tag helpers cannot restrict child elements that contain a '{2}' character. + + Invalid restricted child '{1}' for tag helper '{0}'. Tag helpers cannot restrict child elements that contain a '{2}' character. - + Invalid restricted child for tag helper '{0}'. Name cannot be null or whitespace. - + Tag helpers cannot target attribute name '{0}' because it contains a '{1}' character. - + Targeted attribute name cannot be null or whitespace. - + Tag helpers cannot target parent tag name '{0}' because it contains a '{1}' character. - + Targeted parent tag name cannot be null or whitespace. - + Tag helpers cannot target tag name '{0}' because it contains a '{1}' character. - + Targeted tag name cannot be null or whitespace. diff --git a/src/Microsoft.AspNetCore.Razor.Language/TagHelperBinder.cs b/src/Microsoft.AspNetCore.Razor.Language/TagHelperBinder.cs index d75023fd10..529a80325f 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/TagHelperBinder.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/TagHelperBinder.cs @@ -74,7 +74,7 @@ namespace Microsoft.AspNetCore.Razor.Language } var tagNameWithoutPrefix = _tagHelperPrefix != null ? tagName.Substring(_tagHelperPrefix.Length) : tagName; - Dictionary> applicableDescriptorMappings = null; + Dictionary> applicableDescriptorMappings = null; foreach (var descriptor in descriptors) { var applicableRules = descriptor.TagMatchingRules.Where( @@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.Razor.Language { if (applicableDescriptorMappings == null) { - applicableDescriptorMappings = new Dictionary>(); + applicableDescriptorMappings = new Dictionary>(); } applicableDescriptorMappings[descriptor] = applicableRules; diff --git a/src/Microsoft.AspNetCore.Razor.Language/TagHelperBinding.cs b/src/Microsoft.AspNetCore.Razor.Language/TagHelperBinding.cs index 6e5119a1a3..cb1e76a4c0 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/TagHelperBinding.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/TagHelperBinding.cs @@ -7,13 +7,13 @@ namespace Microsoft.AspNetCore.Razor.Language { public sealed class TagHelperBinding { - private IReadOnlyDictionary> _mappings; + private IReadOnlyDictionary> _mappings; internal TagHelperBinding( string tagName, IEnumerable> attributes, string parentTagName, - IReadOnlyDictionary> mappings, + IReadOnlyDictionary> mappings, string tagHelperPrefix) { TagName = tagName; @@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Razor.Language public string TagHelperPrefix { get; } - public IEnumerable GetBoundRules(TagHelperDescriptor descriptor) + public IEnumerable GetBoundRules(TagHelperDescriptor descriptor) { return _mappings[descriptor]; } diff --git a/src/Microsoft.AspNetCore.Razor.Language/TagHelperConventions.cs b/src/Microsoft.AspNetCore.Razor.Language/TagHelperConventions.cs new file mode 100644 index 0000000000..f2c4e10c72 --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Language/TagHelperConventions.cs @@ -0,0 +1,10 @@ +// 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. + +namespace Microsoft.AspNetCore.Razor.Language +{ + internal static class TagHelperConventions + { + internal const string DefaultKind = "ITagHelper"; + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Language/TagHelperDescriptor.cs b/src/Microsoft.AspNetCore.Razor.Language/TagHelperDescriptor.cs index 45f7eba55f..6ad3528353 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/TagHelperDescriptor.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/TagHelperDescriptor.cs @@ -3,10 +3,12 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; namespace Microsoft.AspNetCore.Razor.Language { + [DebuggerDisplay("{DisplayName,nq}")] public abstract class TagHelperDescriptor : IEquatable { private IEnumerable _allDiagnostics; @@ -20,7 +22,7 @@ namespace Microsoft.AspNetCore.Razor.Language public string Name { get; protected set; } - public IEnumerable TagMatchingRules { get; protected set; } + public IEnumerable TagMatchingRules { get; protected set; } public string AssemblyName { get; protected set; } diff --git a/src/Microsoft.AspNetCore.Razor.Language/TagHelperDescriptorBuilder.cs b/src/Microsoft.AspNetCore.Razor.Language/TagHelperDescriptorBuilder.cs index 82f0f90e70..3f301037c8 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/TagHelperDescriptorBuilder.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/TagHelperDescriptorBuilder.cs @@ -1,273 +1,66 @@ // 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 sealed class TagHelperDescriptorBuilder + public abstract class TagHelperDescriptorBuilder { - internal const string DescriptorKind = "ITagHelper"; - internal const string TypeNameKey = "ITagHelper.TypeName"; - - private string _displayName; - private string _documentation; - private string _tagOutputHint; - private HashSet _allowedChildTags; - private HashSet _attributeDescriptors; - private HashSet _tagMatchingRules; - private readonly string _assemblyName; - private readonly string _typeName; - private readonly Dictionary _metadata; - private HashSet _diagnostics; - - private TagHelperDescriptorBuilder(string typeName, string assemblyName) + public static TagHelperDescriptorBuilder Create(string name, string assemblyName) { - _typeName = typeName; - _displayName = _typeName; - _assemblyName = assemblyName; - _metadata = new Dictionary(StringComparer.Ordinal); - } - - public static TagHelperDescriptorBuilder Create(string typeName, string assemblyName) - { - return new TagHelperDescriptorBuilder(typeName, assemblyName); - } - - public TagHelperDescriptorBuilder BindAttribute(BoundAttributeDescriptor descriptor) - { - if (descriptor == null) + if (name == null) { - throw new ArgumentNullException(nameof(descriptor)); + throw new ArgumentNullException(nameof(name)); } - EnsureAttributeDescriptors(); - _attributeDescriptors.Add(descriptor); - - return this; - } - - public TagHelperDescriptorBuilder BindAttribute(Action configure) - { - if (configure == null) + if (assemblyName == null) { - throw new ArgumentNullException(nameof(configure)); + throw new ArgumentNullException(nameof(assemblyName)); } - var builder = BoundAttributeDescriptorBuilder.Create(_typeName); - - configure(builder); - - var attributeDescriptor = builder.Build(); - - return BindAttribute(attributeDescriptor); + return new DefaultTagHelperDescriptorBuilder(TagHelperConventions.DefaultKind, name, assemblyName); } - public TagHelperDescriptorBuilder TagMatchingRule(TagMatchingRule rule) + public static TagHelperDescriptorBuilder Create(string kind, string name, string assemblyName) { - if (rule == null) + if (kind == null) { - throw new ArgumentNullException(nameof(rule)); + throw new ArgumentNullException(nameof(kind)); } - EnsureTagMatchingRules(); - _tagMatchingRules.Add(rule); - - return this; - } - - public TagHelperDescriptorBuilder TagMatchingRule(Action configure) - { - if (configure == null) + if (name == null) { - throw new ArgumentNullException(nameof(configure)); + throw new ArgumentNullException(nameof(name)); } - var builder = TagMatchingRuleBuilder.Create(); - - configure(builder); - - var rule = builder.Build(); - - return TagMatchingRule(rule); - } - - public TagHelperDescriptorBuilder AllowChildTag(string allowedChild) - { - EnsureAllowedChildTags(); - _allowedChildTags.Add(allowedChild); - - return this; - } - - public TagHelperDescriptorBuilder TagOutputHint(string hint) - { - _tagOutputHint = hint; - - return this; - } - - public TagHelperDescriptorBuilder Documentation(string documentation) - { - _documentation = documentation; - - return this; - } - - public TagHelperDescriptorBuilder AddMetadata(string key, string value) - { - _metadata[key] = value; - - return this; - } - - public TagHelperDescriptorBuilder AddDiagnostic(RazorDiagnostic diagnostic) - { - EnsureDiagnostics(); - _diagnostics.Add(diagnostic); - - return this; - } - - public TagHelperDescriptorBuilder DisplayName(string displayName) - { - if (displayName == null) + if (assemblyName == null) { - throw new ArgumentNullException(nameof(displayName)); + throw new ArgumentNullException(nameof(assemblyName)); } - _displayName = displayName; - - return this; + return new DefaultTagHelperDescriptorBuilder(kind, name, assemblyName); } - public TagHelperDescriptor Build() - { - var validationDiagnostics = Validate(); - var diagnostics = new HashSet(validationDiagnostics); - if (_diagnostics != null) - { - diagnostics.UnionWith(_diagnostics); - } + public abstract TagHelperDescriptorBuilder BindAttribute(Action configure); - var descriptor = new ITagHelperDescriptor( - _typeName, - _assemblyName, - _typeName /* Name */, - _displayName, - _documentation, - _tagOutputHint, - _tagMatchingRules ?? Enumerable.Empty(), - _attributeDescriptors ?? Enumerable.Empty(), - _allowedChildTags ?? Enumerable.Empty(), - _metadata, - diagnostics); + public abstract TagHelperDescriptorBuilder TagMatchingRule(Action configure); - return descriptor; - } + public abstract TagHelperDescriptorBuilder AllowChildTag(string allowedChild); - public void Reset() - { - _documentation = null; - _tagOutputHint = null; - _allowedChildTags?.Clear(); - _attributeDescriptors?.Clear(); - _tagMatchingRules?.Clear(); - _metadata.Clear(); - _diagnostics?.Clear(); - } + public abstract TagHelperDescriptorBuilder TagOutputHint(string hint); - private IEnumerable Validate() - { - if (_allowedChildTags != null) - { - foreach (var name in _allowedChildTags) - { - if (string.IsNullOrWhiteSpace(name)) - { - var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidRestrictedChildNullOrWhitespace(_typeName); + public abstract TagHelperDescriptorBuilder Documentation(string documentation); - yield return diagnostic; - } - else if (name != TagHelperMatchingConventions.ElementCatchAllName) - { - foreach (var character in name) - { - if (char.IsWhiteSpace(character) || HtmlConventions.InvalidNonWhitespaceHtmlCharacters.Contains(character)) - { - var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidRestrictedChild(name, _typeName, character); + public abstract TagHelperDescriptorBuilder AddMetadata(string key, string value); - yield return diagnostic; - } - } - } - } - } - } + public abstract TagHelperDescriptorBuilder AddDiagnostic(RazorDiagnostic diagnostic); - private void EnsureAttributeDescriptors() - { - if (_attributeDescriptors == null) - { - _attributeDescriptors = new HashSet(BoundAttributeDescriptorComparer.Default); - } - } + public abstract TagHelperDescriptorBuilder DisplayName(string displayName); - private void EnsureTagMatchingRules() - { - if (_tagMatchingRules == null) - { - _tagMatchingRules = new HashSet(TagMatchingRuleComparer.Default); - } - } + public abstract TagHelperDescriptorBuilder TypeName(string typeName); - private void EnsureAllowedChildTags() - { - if (_allowedChildTags == null) - { - _allowedChildTags = new HashSet(StringComparer.OrdinalIgnoreCase); - } - } + public abstract TagHelperDescriptor Build(); - private void EnsureDiagnostics() - { - if (_diagnostics == null) - { - _diagnostics = new HashSet(); - } - } - - private class ITagHelperDescriptor : TagHelperDescriptor - { - public ITagHelperDescriptor( - string typeName, - string assemblyName, - string name, - string displayName, - string documentation, - string tagOutputHint, - IEnumerable tagMatchingRules, - IEnumerable attributeDescriptors, - IEnumerable allowedChildTags, - Dictionary metadata, - IEnumerable diagnostics) : base(DescriptorKind) - { - Name = typeName; - AssemblyName = assemblyName; - DisplayName = displayName; - Documentation = documentation; - TagOutputHint = tagOutputHint; - TagMatchingRules = new List(tagMatchingRules); - BoundAttributes = new List(attributeDescriptors); - AllowedChildTags = new List(allowedChildTags); - Diagnostics = new List(diagnostics); - Metadata = new Dictionary(metadata) - { - [TypeNameKey] = typeName - }; - } - } + public abstract void Reset(); } } diff --git a/src/Microsoft.AspNetCore.Razor.Language/TagHelperDescriptorComparer.cs b/src/Microsoft.AspNetCore.Razor.Language/TagHelperDescriptorComparer.cs index 09e822b726..b45aaa2c98 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/TagHelperDescriptorComparer.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/TagHelperDescriptorComparer.cs @@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Razor.Language private readonly StringComparer _stringComparer; private readonly StringComparison _stringComparison; private readonly BoundAttributeDescriptorComparer _boundAttributeComparer; - private readonly TagMatchingRuleComparer _tagMatchingRuleComparer; + private readonly TagMatchingRuleDescriptorComparer _tagMatchingRuleComparer; private TagHelperDescriptorComparer(bool caseSensitive = false) { @@ -33,14 +33,14 @@ namespace Microsoft.AspNetCore.Razor.Language _stringComparer = StringComparer.Ordinal; _stringComparison = StringComparison.Ordinal; _boundAttributeComparer = BoundAttributeDescriptorComparer.CaseSensitive; - _tagMatchingRuleComparer = TagMatchingRuleComparer.CaseSensitive; + _tagMatchingRuleComparer = TagMatchingRuleDescriptorComparer.CaseSensitive; } else { _stringComparer = StringComparer.OrdinalIgnoreCase; _stringComparison = StringComparison.OrdinalIgnoreCase; _boundAttributeComparer = BoundAttributeDescriptorComparer.Default; - _tagMatchingRuleComparer = TagMatchingRuleComparer.Default; + _tagMatchingRuleComparer = TagMatchingRuleDescriptorComparer.Default; } } diff --git a/src/Microsoft.AspNetCore.Razor.Language/TagHelperDescriptorExtensions.cs b/src/Microsoft.AspNetCore.Razor.Language/TagHelperDescriptorExtensions.cs index ead9d6ca62..e08126cbc2 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/TagHelperDescriptorExtensions.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/TagHelperDescriptorExtensions.cs @@ -9,12 +9,14 @@ namespace Microsoft.AspNetCore.Razor.Language { public static string GetTypeName(this TagHelperDescriptor descriptor) { - descriptor.Metadata.TryGetValue(TagHelperDescriptorBuilder.TypeNameKey, out var typeName); + descriptor.Metadata.TryGetValue(TagHelperMetadata.Common.TypeName, out var typeName); return typeName; } public static bool IsDefaultKind(this TagHelperDescriptor descriptor) - => string.Equals(descriptor.Kind, TagHelperDescriptorBuilder.DescriptorKind, StringComparison.Ordinal); + { + return string.Equals(descriptor.Kind, TagHelperConventions.DefaultKind, StringComparison.Ordinal); + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Razor.Language/TagHelperMatchingConventions.cs b/src/Microsoft.AspNetCore.Razor.Language/TagHelperMatchingConventions.cs index c930f0914b..6e6b2442de 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/TagHelperMatchingConventions.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/TagHelperMatchingConventions.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Razor.Language string tagNameWithoutPrefix, string parentTagName, IEnumerable> tagAttributes, - TagMatchingRule rule) + TagMatchingRuleDescriptor rule) { if (tagNameWithoutPrefix == null) { @@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.Razor.Language return true; } - public static bool SatisfiesTagName(string tagNameWithoutPrefix, TagMatchingRule rule) + public static bool SatisfiesTagName(string tagNameWithoutPrefix, TagMatchingRuleDescriptor rule) { if (tagNameWithoutPrefix == null) { @@ -89,7 +89,7 @@ namespace Microsoft.AspNetCore.Razor.Language return true; } - public static bool SatisfiesParentTag(string parentTagName, TagMatchingRule rule) + public static bool SatisfiesParentTag(string parentTagName, TagMatchingRuleDescriptor rule) { if (rule == null) { @@ -104,7 +104,7 @@ namespace Microsoft.AspNetCore.Razor.Language return true; } - public static bool SatisfiesAttributes(IEnumerable> tagAttributes, TagMatchingRule rule) + public static bool SatisfiesAttributes(IEnumerable> tagAttributes, TagMatchingRuleDescriptor rule) { if (tagAttributes == null) { diff --git a/src/Microsoft.AspNetCore.Razor.Language/TagHelperMetadata.cs b/src/Microsoft.AspNetCore.Razor.Language/TagHelperMetadata.cs new file mode 100644 index 0000000000..d51b795caa --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Language/TagHelperMetadata.cs @@ -0,0 +1,15 @@ +// 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. + +namespace Microsoft.AspNetCore.Razor.Language +{ + internal static class TagHelperMetadata + { + public static class Common + { + internal const string PropertyName = "Common.PropertyName"; + + internal const string TypeName = "Common.TypeName"; + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Language/TagMatchingRule.cs b/src/Microsoft.AspNetCore.Razor.Language/TagMatchingRuleDescriptor.cs similarity index 81% rename from src/Microsoft.AspNetCore.Razor.Language/TagMatchingRule.cs rename to src/Microsoft.AspNetCore.Razor.Language/TagMatchingRuleDescriptor.cs index 998690fefd..847eb294f1 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/TagMatchingRule.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/TagMatchingRuleDescriptor.cs @@ -7,7 +7,7 @@ using System.Linq; namespace Microsoft.AspNetCore.Razor.Language { - public abstract class TagMatchingRule : IEquatable + public abstract class TagMatchingRuleDescriptor : IEquatable { private IEnumerable _allDiagnostics; @@ -44,19 +44,19 @@ namespace Microsoft.AspNetCore.Razor.Language return _allDiagnostics; } - public bool Equals(TagMatchingRule other) + public bool Equals(TagMatchingRuleDescriptor other) { - return TagMatchingRuleComparer.Default.Equals(this, other); + return TagMatchingRuleDescriptorComparer.Default.Equals(this, other); } public override bool Equals(object obj) { - return Equals(obj as TagMatchingRule); + return Equals(obj as TagMatchingRuleDescriptor); } public override int GetHashCode() { - return TagMatchingRuleComparer.Default.GetHashCode(this); + return TagMatchingRuleDescriptorComparer.Default.GetHashCode(this); } } } diff --git a/src/Microsoft.AspNetCore.Razor.Language/TagMatchingRuleDescriptorBuilder.cs b/src/Microsoft.AspNetCore.Razor.Language/TagMatchingRuleDescriptorBuilder.cs new file mode 100644 index 0000000000..d3cab36921 --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Language/TagMatchingRuleDescriptorBuilder.cs @@ -0,0 +1,20 @@ +// 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 +{ + public abstract class TagMatchingRuleDescriptorBuilder + { + public abstract TagMatchingRuleDescriptorBuilder RequireTagName(string tagName); + + public abstract TagMatchingRuleDescriptorBuilder RequireParentTag(string parentTag); + + public abstract TagMatchingRuleDescriptorBuilder RequireTagStructure(TagStructure tagStructure); + + public abstract TagMatchingRuleDescriptorBuilder RequireAttribute(Action configure); + + public abstract TagMatchingRuleDescriptorBuilder AddDiagnostic(RazorDiagnostic diagnostic); + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Language/TagMatchingRuleComparer.cs b/src/Microsoft.AspNetCore.Razor.Language/TagMatchingRuleDescriptorComparer.cs similarity index 79% rename from src/Microsoft.AspNetCore.Razor.Language/TagMatchingRuleComparer.cs rename to src/Microsoft.AspNetCore.Razor.Language/TagMatchingRuleDescriptorComparer.cs index e1a3d1c49a..c77bdfbddb 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/TagMatchingRuleComparer.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/TagMatchingRuleDescriptorComparer.cs @@ -9,24 +9,24 @@ using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Razor.Language { - internal class TagMatchingRuleComparer : IEqualityComparer + internal class TagMatchingRuleDescriptorComparer : IEqualityComparer { /// - /// A default instance of the . + /// A default instance of the . /// - public static readonly TagMatchingRuleComparer Default = new TagMatchingRuleComparer(); + public static readonly TagMatchingRuleDescriptorComparer Default = new TagMatchingRuleDescriptorComparer(); /// - /// A default instance of the that does case-sensitive comparison. + /// A default instance of the that does case-sensitive comparison. /// - internal static readonly TagMatchingRuleComparer CaseSensitive = - new TagMatchingRuleComparer(caseSensitive: true); + internal static readonly TagMatchingRuleDescriptorComparer CaseSensitive = + new TagMatchingRuleDescriptorComparer(caseSensitive: true); private readonly StringComparer _stringComparer; private readonly StringComparison _stringComparison; private readonly RequiredAttributeDescriptorComparer _requiredAttributeComparer; - private TagMatchingRuleComparer(bool caseSensitive = false) + private TagMatchingRuleDescriptorComparer(bool caseSensitive = false) { if (caseSensitive) { @@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Razor.Language } } - public virtual bool Equals(TagMatchingRule ruleX, TagMatchingRule ruleY) + public virtual bool Equals(TagMatchingRuleDescriptor ruleX, TagMatchingRuleDescriptor ruleY) { if (object.ReferenceEquals(ruleX, ruleY)) { @@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Razor.Language Enumerable.SequenceEqual(ruleX.Diagnostics, ruleY.Diagnostics); } - public virtual int GetHashCode(TagMatchingRule rule) + public virtual int GetHashCode(TagMatchingRuleDescriptor rule) { if (rule == null) { diff --git a/src/Microsoft.CodeAnalysis.Razor/DefaultTagHelperDescriptorFactory.cs b/src/Microsoft.CodeAnalysis.Razor/DefaultTagHelperDescriptorFactory.cs index 148e35a557..f2cf712ceb 100644 --- a/src/Microsoft.CodeAnalysis.Razor/DefaultTagHelperDescriptorFactory.cs +++ b/src/Microsoft.CodeAnalysis.Razor/DefaultTagHelperDescriptorFactory.cs @@ -58,6 +58,7 @@ namespace Microsoft.CodeAnalysis.Razor var typeName = GetFullName(type); var assemblyName = type.ContainingAssembly.Identity.Name; var descriptorBuilder = TagHelperDescriptorBuilder.Create(typeName, assemblyName); + descriptorBuilder.TypeName(typeName); AddBoundAttributes(type, descriptorBuilder); AddTagMatchingRules(type, descriptorBuilder); diff --git a/src/Microsoft.CodeAnalysis.Razor/Properties/Resources.Designer.cs b/src/Microsoft.CodeAnalysis.Razor/Properties/Resources.Designer.cs index 4c8094d092..df00f34c36 100644 --- a/src/Microsoft.CodeAnalysis.Razor/Properties/Resources.Designer.cs +++ b/src/Microsoft.CodeAnalysis.Razor/Properties/Resources.Designer.cs @@ -13,114 +13,114 @@ namespace Microsoft.CodeAnalysis.Razor /// /// Could not find matching ']' for required attribute '{0}'. /// - internal static string TagHelperDescriptorFactory_CouldNotFindMatchingEndBrace + internal static string TagHelper_CouldNotFindMatchingEndBrace { - get => GetString("TagHelperDescriptorFactory_CouldNotFindMatchingEndBrace"); + get => GetString("TagHelper_CouldNotFindMatchingEndBrace"); } /// /// Could not find matching ']' for required attribute '{0}'. /// - internal static string FormatTagHelperDescriptorFactory_CouldNotFindMatchingEndBrace(object p0) - => string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_CouldNotFindMatchingEndBrace"), p0); + internal static string FormatTagHelper_CouldNotFindMatchingEndBrace(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("TagHelper_CouldNotFindMatchingEndBrace"), p0); /// - /// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null unless property type implements '{4}'. + /// Invalid tag helper bound property '{1}' on tag helper '{0}'. '{2}.{3}' must be null unless property type implements '{4}'. /// - internal static string TagHelperDescriptorFactory_InvalidAttributePrefixNotNull + internal static string TagHelper_InvalidAttributePrefixNotNull { - get => GetString("TagHelperDescriptorFactory_InvalidAttributePrefixNotNull"); + get => GetString("TagHelper_InvalidAttributePrefixNotNull"); } /// - /// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null unless property type implements '{4}'. + /// Invalid tag helper bound property '{1}' on tag helper '{0}'. '{2}.{3}' must be null unless property type implements '{4}'. /// - internal static string FormatTagHelperDescriptorFactory_InvalidAttributePrefixNotNull(object p0, object p1, object p2, object p3, object p4) - => string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidAttributePrefixNotNull"), p0, p1, p2, p3, p4); + internal static string FormatTagHelper_InvalidAttributePrefixNotNull(object p0, object p1, object p2, object p3, object p4) + => string.Format(CultureInfo.CurrentCulture, GetString("TagHelper_InvalidAttributePrefixNotNull"), p0, p1, p2, p3, p4); /// - /// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null or empty if property has no public setter. + /// Invalid tag helper bound property '{1}' on tag helper '{0}'. '{2}.{3}' must be null or empty if property has no public setter. /// - internal static string TagHelperDescriptorFactory_InvalidAttributeNameNotNullOrEmpty + internal static string TagHelper_InvalidAttributeNameNotNullOrEmpty { - get => GetString("TagHelperDescriptorFactory_InvalidAttributeNameNotNullOrEmpty"); + get => GetString("TagHelper_InvalidAttributeNameNotNullOrEmpty"); } /// - /// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null or empty if property has no public setter. + /// Invalid tag helper bound property '{1}' on tag helper '{0}'. '{2}.{3}' must be null or empty if property has no public setter. /// - internal static string FormatTagHelperDescriptorFactory_InvalidAttributeNameNotNullOrEmpty(object p0, object p1, object p2, object p3) - => string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidAttributeNameNotNullOrEmpty"), p0, p1, p2, p3); + internal static string FormatTagHelper_InvalidAttributeNameNotNullOrEmpty(object p0, object p1, object p2, object p3) + => string.Format(CultureInfo.CurrentCulture, GetString("TagHelper_InvalidAttributeNameNotNullOrEmpty"), p0, p1, p2, p3); /// - /// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must not be null if property has no public setter and its type implements '{4}'. + /// Invalid tag helper bound property '{1}' on tag helper '{0}'. '{2}.{3}' must not be null if property has no public setter and its type implements '{4}'. /// - internal static string TagHelperDescriptorFactory_InvalidAttributePrefixNull + internal static string TagHelper_InvalidAttributePrefixNull { - get => GetString("TagHelperDescriptorFactory_InvalidAttributePrefixNull"); + get => GetString("TagHelper_InvalidAttributePrefixNull"); } /// - /// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must not be null if property has no public setter and its type implements '{4}'. + /// Invalid tag helper bound property '{1}' on tag helper '{0}'. '{2}.{3}' must not be null if property has no public setter and its type implements '{4}'. /// - internal static string FormatTagHelperDescriptorFactory_InvalidAttributePrefixNull(object p0, object p1, object p2, object p3, object p4) - => string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidAttributePrefixNull"), p0, p1, p2, p3, p4); + internal static string FormatTagHelper_InvalidAttributePrefixNull(object p0, object p1, object p2, object p3, object p4) + => string.Format(CultureInfo.CurrentCulture, GetString("TagHelper_InvalidAttributePrefixNull"), p0, p1, p2, p3, p4); /// /// Invalid required attribute character '{0}' in required attribute '{1}'. Separate required attributes with commas. /// - internal static string TagHelperDescriptorFactory_InvalidRequiredAttributeCharacter + internal static string TagHelper_InvalidRequiredAttributeCharacter { - get => GetString("TagHelperDescriptorFactory_InvalidRequiredAttributeCharacter"); + get => GetString("TagHelper_InvalidRequiredAttributeCharacter"); } /// /// Invalid required attribute character '{0}' in required attribute '{1}'. Separate required attributes with commas. /// - internal static string FormatTagHelperDescriptorFactory_InvalidRequiredAttributeCharacter(object p0, object p1) - => string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidRequiredAttributeCharacter"), p0, p1); + internal static string FormatTagHelper_InvalidRequiredAttributeCharacter(object p0, object p1) + => string.Format(CultureInfo.CurrentCulture, GetString("TagHelper_InvalidRequiredAttributeCharacter"), p0, p1); /// /// Required attribute '{0}' has mismatched quotes '{1}' around value. /// - internal static string TagHelperDescriptorFactory_InvalidRequiredAttributeMismatchedQuotes + internal static string TagHelper_InvalidRequiredAttributeMismatchedQuotes { - get => GetString("TagHelperDescriptorFactory_InvalidRequiredAttributeMismatchedQuotes"); + get => GetString("TagHelper_InvalidRequiredAttributeMismatchedQuotes"); } /// /// Required attribute '{0}' has mismatched quotes '{1}' around value. /// - internal static string FormatTagHelperDescriptorFactory_InvalidRequiredAttributeMismatchedQuotes(object p0, object p1) - => string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidRequiredAttributeMismatchedQuotes"), p0, p1); + internal static string FormatTagHelper_InvalidRequiredAttributeMismatchedQuotes(object p0, object p1) + => string.Format(CultureInfo.CurrentCulture, GetString("TagHelper_InvalidRequiredAttributeMismatchedQuotes"), p0, p1); /// /// Invalid character '{0}' in required attribute '{1}'. Expected supported CSS operator or ']'. /// - internal static string TagHelperDescriptorFactory_InvalidRequiredAttributeOperator + internal static string TagHelper_InvalidRequiredAttributeOperator { - get => GetString("TagHelperDescriptorFactory_InvalidRequiredAttributeOperator"); + get => GetString("TagHelper_InvalidRequiredAttributeOperator"); } /// /// Invalid character '{0}' in required attribute '{1}'. Expected supported CSS operator or ']'. /// - internal static string FormatTagHelperDescriptorFactory_InvalidRequiredAttributeOperator(object p0, object p1) - => string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidRequiredAttributeOperator"), p0, p1); + internal static string FormatTagHelper_InvalidRequiredAttributeOperator(object p0, object p1) + => string.Format(CultureInfo.CurrentCulture, GetString("TagHelper_InvalidRequiredAttributeOperator"), p0, p1); /// /// Required attribute '{0}' has a partial CSS operator. '{1}' must be followed by an equals. /// - internal static string TagHelperDescriptorFactory_PartialRequiredAttributeOperator + internal static string TagHelper_PartialRequiredAttributeOperator { - get => GetString("TagHelperDescriptorFactory_PartialRequiredAttributeOperator"); + get => GetString("TagHelper_PartialRequiredAttributeOperator"); } /// /// Required attribute '{0}' has a partial CSS operator. '{1}' must be followed by an equals. /// - internal static string FormatTagHelperDescriptorFactory_PartialRequiredAttributeOperator(object p0, object p1) - => string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_PartialRequiredAttributeOperator"), p0, p1); + internal static string FormatTagHelper_PartialRequiredAttributeOperator(object p0, object p1) + => string.Format(CultureInfo.CurrentCulture, GetString("TagHelper_PartialRequiredAttributeOperator"), p0, p1); private static string GetString(string name, params string[] formatterNames) { diff --git a/src/Microsoft.CodeAnalysis.Razor/RazorDiagnosticFactory.cs b/src/Microsoft.CodeAnalysis.Razor/RazorDiagnosticFactory.cs index e57e28439d..12fa708189 100644 --- a/src/Microsoft.CodeAnalysis.Razor/RazorDiagnosticFactory.cs +++ b/src/Microsoft.CodeAnalysis.Razor/RazorDiagnosticFactory.cs @@ -44,36 +44,36 @@ namespace Microsoft.CodeAnalysis.Razor * TagHelper Errors ID Offset = 3500 */ - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidAttributeNameNullOrEmpty = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidAttributeNameNullOrEmpty = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3500", - () => Resources.TagHelperDescriptorFactory_InvalidAttributeNameNotNullOrEmpty, + () => Resources.TagHelper_InvalidAttributeNameNotNullOrEmpty, RazorDiagnosticSeverity.Error); - public static RazorDiagnostic CreateTagHelper_InvalidAttributeNameNullOrEmpty(string containingTypeName, string boundPropertyName) + public static RazorDiagnostic CreateTagHelper_InvalidAttributeNameNullOrEmpty(string tagHelperDisplayName, string propertyDisplayName) { var diagnostic = RazorDiagnostic.Create( TagHelper_InvalidAttributeNameNullOrEmpty, new SourceSpan(SourceLocation.Undefined, contentLength: 0), - containingTypeName, - boundPropertyName, + tagHelperDisplayName, + propertyDisplayName, TagHelperTypes.HtmlAttributeNameAttribute, TagHelperTypes.HtmlAttributeName.Name); return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidAttributePrefixNotNull = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidAttributePrefixNotNull = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3501", - () => Resources.TagHelperDescriptorFactory_InvalidAttributePrefixNotNull, + () => Resources.TagHelper_InvalidAttributePrefixNotNull, RazorDiagnosticSeverity.Error); - public static RazorDiagnostic CreateTagHelper_InvalidAttributePrefixNotNull(string containingTypeName, string boundPropertyName) + public static RazorDiagnostic CreateTagHelper_InvalidAttributePrefixNotNull(string tagHelperDisplayName, string propertyDisplayName) { var diagnostic = RazorDiagnostic.Create( TagHelper_InvalidAttributePrefixNotNull, new SourceSpan(SourceLocation.Undefined, contentLength: 0), - containingTypeName, - boundPropertyName, + tagHelperDisplayName, + propertyDisplayName, TagHelperTypes.HtmlAttributeNameAttribute, TagHelperTypes.HtmlAttributeName.DictionaryAttributePrefix, "IDictionary"); @@ -81,18 +81,18 @@ namespace Microsoft.CodeAnalysis.Razor return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidAttributePrefixNull = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidAttributePrefixNull = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3502", - () => Resources.TagHelperDescriptorFactory_InvalidAttributePrefixNull, + () => Resources.TagHelper_InvalidAttributePrefixNull, RazorDiagnosticSeverity.Error); - public static RazorDiagnostic CreateTagHelper_InvalidAttributePrefixNull(string containingTypeName, string boundPropertyName) + public static RazorDiagnostic CreateTagHelper_InvalidAttributePrefixNull(string tagHelperDisplayName, string propertyDisplayName) { var diagnostic = RazorDiagnostic.Create( TagHelper_InvalidAttributePrefixNull, new SourceSpan(SourceLocation.Undefined, contentLength: 0), - containingTypeName, - boundPropertyName, + tagHelperDisplayName, + propertyDisplayName, TagHelperTypes.HtmlAttributeNameAttribute, TagHelperTypes.HtmlAttributeName.DictionaryAttributePrefix, "IDictionary"); @@ -100,10 +100,10 @@ namespace Microsoft.CodeAnalysis.Razor return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidRequiredAttributeCharacter = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidRequiredAttributeCharacter = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3503", - () => Resources.TagHelperDescriptorFactory_InvalidRequiredAttributeCharacter, + () => Resources.TagHelper_InvalidRequiredAttributeCharacter, RazorDiagnosticSeverity.Error); public static RazorDiagnostic CreateTagHelper_InvalidRequiredAttributeCharacter(char invalidCharacter, string requiredAttributes) { @@ -116,10 +116,10 @@ namespace Microsoft.CodeAnalysis.Razor return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_PartialRequiredAttributeOperator = + internal static readonly RazorDiagnosticDescriptor TagHelper_PartialRequiredAttributeOperator = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3504", - () => Resources.TagHelperDescriptorFactory_PartialRequiredAttributeOperator, + () => Resources.TagHelper_PartialRequiredAttributeOperator, RazorDiagnosticSeverity.Error); public static RazorDiagnostic CreateTagHelper_PartialRequiredAttributeOperator(char partialOperator, string requiredAttributes) { @@ -132,10 +132,10 @@ namespace Microsoft.CodeAnalysis.Razor return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidRequiredAttributeOperator = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidRequiredAttributeOperator = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3505", - () => Resources.TagHelperDescriptorFactory_InvalidRequiredAttributeOperator, + () => Resources.TagHelper_InvalidRequiredAttributeOperator, RazorDiagnosticSeverity.Error); public static RazorDiagnostic CreateTagHelper_InvalidRequiredAttributeOperator(char invalidOperator, string requiredAttributes) { @@ -148,10 +148,10 @@ namespace Microsoft.CodeAnalysis.Razor return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_InvalidRequiredAttributeMismatchedQuotes = + internal static readonly RazorDiagnosticDescriptor TagHelper_InvalidRequiredAttributeMismatchedQuotes = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3506", - () => Resources.TagHelperDescriptorFactory_InvalidRequiredAttributeMismatchedQuotes, + () => Resources.TagHelper_InvalidRequiredAttributeMismatchedQuotes, RazorDiagnosticSeverity.Error); public static RazorDiagnostic CreateTagHelper_InvalidRequiredAttributeMismatchedQuotes(char quote, string requiredAttributes) { @@ -164,10 +164,10 @@ namespace Microsoft.CodeAnalysis.Razor return diagnostic; } - private static readonly RazorDiagnosticDescriptor TagHelper_CouldNotFindMatchingEndBrace = + internal static readonly RazorDiagnosticDescriptor TagHelper_CouldNotFindMatchingEndBrace = new RazorDiagnosticDescriptor( $"{DiagnosticPrefix}3507", - () => Resources.TagHelperDescriptorFactory_CouldNotFindMatchingEndBrace, + () => Resources.TagHelper_CouldNotFindMatchingEndBrace, RazorDiagnosticSeverity.Error); public static RazorDiagnostic CreateTagHelper_CouldNotFindMatchingEndBrace(string requiredAttributes) { diff --git a/src/Microsoft.CodeAnalysis.Razor/RequiredAttributeParser.cs b/src/Microsoft.CodeAnalysis.Razor/RequiredAttributeParser.cs index 9c3653aecb..1946a723b5 100644 --- a/src/Microsoft.CodeAnalysis.Razor/RequiredAttributeParser.cs +++ b/src/Microsoft.CodeAnalysis.Razor/RequiredAttributeParser.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.Razor // Internal for testing internal static class RequiredAttributeParser { - public static void AddRequiredAttributes(string requiredAttributes, TagMatchingRuleBuilder ruleBuilder) + public static void AddRequiredAttributes(string requiredAttributes, TagMatchingRuleDescriptorBuilder ruleBuilder) { var requiredAttributeParser = new DefaultRequiredAttributeParser(requiredAttributes); requiredAttributeParser.AddRequiredAttributes(ruleBuilder); @@ -46,7 +46,7 @@ namespace Microsoft.CodeAnalysis.Razor private bool AtEnd => _index >= _requiredAttributes.Length; - public void AddRequiredAttributes(TagMatchingRuleBuilder ruleBuilder) + public void AddRequiredAttributes(TagMatchingRuleDescriptorBuilder ruleBuilder) { if (string.IsNullOrEmpty(_requiredAttributes)) { diff --git a/src/Microsoft.CodeAnalysis.Razor/Resources.resx b/src/Microsoft.CodeAnalysis.Razor/Resources.resx index edfa6f2970..fd92b354d9 100644 --- a/src/Microsoft.CodeAnalysis.Razor/Resources.resx +++ b/src/Microsoft.CodeAnalysis.Razor/Resources.resx @@ -117,28 +117,28 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + Could not find matching ']' for required attribute '{0}'. - - Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null unless property type implements '{4}'. + + Invalid tag helper bound property '{1}' on tag helper '{0}'. '{2}.{3}' must be null unless property type implements '{4}'. - - Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null or empty if property has no public setter. + + Invalid tag helper bound property '{1}' on tag helper '{0}'. '{2}.{3}' must be null or empty if property has no public setter. - - Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must not be null if property has no public setter and its type implements '{4}'. + + Invalid tag helper bound property '{1}' on tag helper '{0}'. '{2}.{3}' must not be null if property has no public setter and its type implements '{4}'. - + Invalid required attribute character '{0}' in required attribute '{1}'. Separate required attributes with commas. - + Required attribute '{0}' has mismatched quotes '{1}' around value. - + Invalid character '{0}' in required attribute '{1}'. Expected supported CSS operator or ']'. - + Required attribute '{0}' has a partial CSS operator. '{1}' must be followed by an equals. \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.LanguageServices.Razor/TagHelperDescriptorJsonConverter.cs b/src/Microsoft.VisualStudio.LanguageServices.Razor/TagHelperDescriptorJsonConverter.cs index 639270b2f6..572459e707 100644 --- a/src/Microsoft.VisualStudio.LanguageServices.Razor/TagHelperDescriptorJsonConverter.cs +++ b/src/Microsoft.VisualStudio.LanguageServices.Razor/TagHelperDescriptorJsonConverter.cs @@ -87,13 +87,13 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor throw new NotImplementedException(); } - private void ReadTagMatchingRule(TagMatchingRuleBuilder builder, JObject rule, JsonSerializer serializer) + private void ReadTagMatchingRule(TagMatchingRuleDescriptorBuilder builder, JObject rule, JsonSerializer serializer) { - var tagName = rule[nameof(TagMatchingRule.TagName)].Value(); - var attributes = rule[nameof(TagMatchingRule.Attributes)].Value(); - var parentTag = rule[nameof(TagMatchingRule.ParentTag)].Value(); - var tagStructure = rule[nameof(TagMatchingRule.TagStructure)].Value(); - var diagnostics = rule[nameof(TagMatchingRule.Diagnostics)].Value(); + var tagName = rule[nameof(TagMatchingRuleDescriptor.TagName)].Value(); + var attributes = rule[nameof(TagMatchingRuleDescriptor.Attributes)].Value(); + var parentTag = rule[nameof(TagMatchingRuleDescriptor.ParentTag)].Value(); + var tagStructure = rule[nameof(TagMatchingRuleDescriptor.TagStructure)].Value(); + var diagnostics = rule[nameof(TagMatchingRuleDescriptor.Diagnostics)].Value(); builder .RequireTagName(tagName) @@ -139,11 +139,6 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor private void ReadBoundAttribute(BoundAttributeDescriptorBuilder builder, JObject attribute, JsonSerializer serializer) { var descriptorKind = attribute[nameof(BoundAttributeDescriptor.Kind)].Value(); - if (descriptorKind != BoundAttributeDescriptorBuilder.DescriptorKind) - { - throw new NotSupportedException(); - } - var name = attribute[nameof(BoundAttributeDescriptor.Name)].Value(); var typeName = attribute[nameof(BoundAttributeDescriptor.TypeName)].Value(); var isEnum = attribute[nameof(BoundAttributeDescriptor.IsEnum)].Value(); @@ -181,9 +176,6 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor { builder.AddMetadata(item.Key, item.Value); } - - var propertyName = metadataValue[BoundAttributeDescriptorBuilder.PropertyNameKey]; - builder.PropertyName(propertyName); } } } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/InstrumentationPassIntegrationTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/InstrumentationPassIntegrationTest.cs index 5059869898..1ce20724f2 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/InstrumentationPassIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/IntegrationTests/InstrumentationPassIntegrationTest.cs @@ -72,6 +72,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.IntegrationTests IEnumerable> attributes = null) { var builder = TagHelperDescriptorBuilder.Create(typeName, assemblyName); + builder.TypeName(typeName); if (attributes != null) { diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TagHelperDescriptorExtensionsTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TagHelperDescriptorExtensionsTest.cs new file mode 100644 index 0000000000..7fea99dae3 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/TagHelperDescriptorExtensionsTest.cs @@ -0,0 +1,82 @@ +// 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 Microsoft.AspNetCore.Razor.Language; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.Razor.Extensions +{ + public class TagHelperDescriptorExtensionsTest + { + [Fact] + public void IsViewComponentKind_ReturnsFalse_ForNonVCTHDescriptor() + { + //Arrange + var tagHelper = CreateTagHelperDescriptor(); + + // Act + var result = tagHelper.IsViewComponentKind(); + + // Assert + Assert.False(result); + } + + [Fact] + public void IsViewComponentKind_ReturnsTrue_ForVCTHDescriptor() + { + // Arrange + var tagHelper = CreateViewComponentTagHelperDescriptor(); + + // Act + var result = tagHelper.IsViewComponentKind(); + + // Assert + Assert.True(result); + } + + [Fact] + public void GetViewComponentName_ReturnsNull_ForNonVCTHDescriptor() + { + //Arrange + var tagHelper = CreateTagHelperDescriptor(); + + // Act + var result = tagHelper.GetViewComponentName(); + + // Assert + Assert.Null(result); + } + + [Fact] + public void GetViewComponentName_ReturnsName_ForVCTHDescriptor() + { + // Arrange + var tagHelper = CreateViewComponentTagHelperDescriptor("ViewComponentName"); + + // Act + var result = tagHelper.GetViewComponentName(); + + // Assert + Assert.Equal("ViewComponentName", result); + } + + private static TagHelperDescriptor CreateTagHelperDescriptor() + { + var descriptor = TagHelperDescriptorBuilder.Create("TypeName", "AssemblyName") + .TagMatchingRule(rule => rule.RequireTagName("tag-name")) + .Build(); + + return descriptor; + } + + private static TagHelperDescriptor CreateViewComponentTagHelperDescriptor(string name = "ViewComponentName") + { + var descriptor = TagHelperDescriptorBuilder.Create(ViewComponentTagHelperConventions.Kind, "TypeName", "AssemblyName") + .TagMatchingRule(rule => rule.RequireTagName("tag-name")) + .AddMetadata(ViewComponentTagHelperMetadata.Name, name) + .Build(); + + return descriptor; + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperDescriptorConventionsTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperDescriptorConventionsTest.cs deleted file mode 100644 index f0bd076179..0000000000 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperDescriptorConventionsTest.cs +++ /dev/null @@ -1,61 +0,0 @@ -// 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 Microsoft.AspNetCore.Razor.Language; -using Xunit; - -namespace Microsoft.AspNetCore.Mvc.Razor.Extensions -{ - public class ViewComponentTagHelperDescriptorConventionsTest - { - [Fact] - public void IsViewComponentDescriptor_ReturnsFalseForInvalidDescriptor() - { - //Arrange - var tagHelperDescriptor = CreateTagHelperDescriptor(); - - // Act - var isViewComponentDescriptor = ViewComponentTagHelperDescriptorConventions - .IsViewComponentDescriptor(tagHelperDescriptor); - - // Assert - Assert.False(isViewComponentDescriptor); - } - - [Fact] - public void IsViewComponentDescriptor_ReturnsTrueForValidDescriptor() - { - // Arrange - var descriptor = CreateViewComponentTagHelperDescriptor(); - - // Act - var isViewComponentDescriptor = ViewComponentTagHelperDescriptorConventions - .IsViewComponentDescriptor(descriptor); - - // Assert - Assert.True(isViewComponentDescriptor); - } - - private static TagHelperDescriptor CreateTagHelperDescriptor() - { - var descriptor = TagHelperDescriptorBuilder.Create("TypeName", "AssemblyName") - .TagMatchingRule(rule => - rule.RequireTagName("tag-name")) - .Build(); - - - return descriptor; - } - - private static TagHelperDescriptor CreateViewComponentTagHelperDescriptor() - { - var descriptor = TagHelperDescriptorBuilder.Create("TypeName", "AssemblyName") - .TagMatchingRule(rule => - rule.RequireTagName("tag-name")) - .AddMetadata(ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey, "ViewComponentName") - .Build(); - - return descriptor; - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperDescriptorFactoryTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperDescriptorFactoryTest.cs index fcfd3b7bf9..b4996badc1 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperDescriptorFactoryTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperDescriptorFactoryTest.cs @@ -21,9 +21,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions var testCompilation = TestCompilation.Create(_assembly); var viewComponent = testCompilation.GetTypeByMetadataName(typeof(StringParameterViewComponent).FullName); var factory = new ViewComponentTagHelperDescriptorFactory(testCompilation); + var expectedDescriptor = TagHelperDescriptorBuilder.Create( + ViewComponentTagHelperConventions.Kind, "__Generated__StringParameterViewComponentTagHelper", typeof(StringParameterViewComponent).GetTypeInfo().Assembly.GetName().Name) + .TypeName("__Generated__StringParameterViewComponentTagHelper") .DisplayName("StringParameterViewComponentTagHelper") .TagMatchingRule(rule => rule @@ -42,7 +45,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions .PropertyName("bar") .TypeName(typeof(string).FullName) .DisplayName("string StringParameterViewComponentTagHelper.bar")) - .AddMetadata(ViewComponentTypes.ViewComponentNameKey, "StringParameter") + .AddMetadata(ViewComponentTagHelperMetadata.Name, "StringParameter") .Build(); // Act @@ -59,9 +62,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions var testCompilation = TestCompilation.Create(_assembly); var viewComponent = testCompilation.GetTypeByMetadataName(typeof(VariousParameterViewComponent).FullName); var factory = new ViewComponentTagHelperDescriptorFactory(testCompilation); + var expectedDescriptor = TagHelperDescriptorBuilder.Create( + ViewComponentTagHelperConventions.Kind, "__Generated__VariousParameterViewComponentTagHelper", typeof(VariousParameterViewComponent).GetTypeInfo().Assembly.GetName().Name) + .TypeName("__Generated__VariousParameterViewComponentTagHelper") .DisplayName("VariousParameterViewComponentTagHelper") .TagMatchingRule(rule => rule @@ -88,7 +94,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions .PropertyName("baz") .TypeName(typeof(int).FullName) .DisplayName("int VariousParameterViewComponentTagHelper.baz")) - .AddMetadata(ViewComponentTypes.ViewComponentNameKey, "VariousParameter") + .AddMetadata(ViewComponentTagHelperMetadata.Name, "VariousParameter") .Build(); // Act @@ -105,9 +111,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions var testCompilation = TestCompilation.Create(_assembly); var viewComponent = testCompilation.GetTypeByMetadataName(typeof(GenericParameterViewComponent).FullName); var factory = new ViewComponentTagHelperDescriptorFactory(testCompilation); + var expectedDescriptor = TagHelperDescriptorBuilder.Create( + ViewComponentTagHelperConventions.Kind, "__Generated__GenericParameterViewComponentTagHelper", typeof(GenericParameterViewComponent).GetTypeInfo().Assembly.GetName().Name) + .TypeName("__Generated__GenericParameterViewComponentTagHelper") .DisplayName("GenericParameterViewComponentTagHelper") .TagMatchingRule(rule => rule @@ -126,7 +135,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions .TypeName("System.Collections.Generic.Dictionary") .AsDictionary("bar-", typeof(int).FullName) .DisplayName("System.Collections.Generic.Dictionary GenericParameterViewComponentTagHelper.Bar")) - .AddMetadata(ViewComponentTypes.ViewComponentNameKey, "GenericParameter") + .AddMetadata(ViewComponentTagHelperMetadata.Name, "GenericParameter") .Build(); // Act diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperDescriptorProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperDescriptorProviderTest.cs index fe5ec8b068..cc2e0da6cf 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperDescriptorProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperDescriptorProviderTest.cs @@ -39,8 +39,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions }; var expectedDescriptor = TagHelperDescriptorBuilder.Create( + ViewComponentTagHelperConventions.Kind, "__Generated__StringParameterViewComponentTagHelper", TestCompilation.AssemblyName) + .TypeName("__Generated__StringParameterViewComponentTagHelper") .DisplayName("StringParameterViewComponentTagHelper") .TagMatchingRule(rule => rule @@ -59,7 +61,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions .PropertyName("bar") .TypeName(typeof(string).FullName) .DisplayName("string StringParameterViewComponentTagHelper.bar")) - .AddMetadata(ViewComponentTypes.ViewComponentNameKey, "StringParameter") + .AddMetadata(ViewComponentTagHelperMetadata.Name, "StringParameter") .Build(); // Act diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperPassTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperPassTest.cs index 1d083bf63c..52f22cb8ff 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperPassTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Extensions.Test/ViewComponentTagHelperPassTest.cs @@ -22,12 +22,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions var tagHelpers = new[] { TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly") - .BindAttribute(attribute => - attribute - .Name("Foo") - .TypeName("System.Int32")) - .TagMatchingRule(rule => - rule.RequireTagName("p")) + .BindAttribute(attribute => attribute + .Name("Foo") + .TypeName("System.Int32")) + .TagMatchingRule(rule => rule.RequireTagName("p")) .Build() }; @@ -61,15 +59,13 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions var tagHelpers = new[] { - TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly") - .BindAttribute(attribute => - attribute - .Name("Foo") - .TypeName("System.Int32") - .PropertyName("Foo")) - .TagMatchingRule(rule => - rule.RequireTagName("tagcloud")) - .AddMetadata(ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey, "TagCloud") + TagHelperDescriptorBuilder.Create(ViewComponentTagHelperConventions.Kind, "TestTagHelper", "TestAssembly") + .BindAttribute(attribute => attribute + .Name("Foo") + .TypeName("System.Int32") + .PropertyName("Foo")) + .TagMatchingRule(rule => rule.RequireTagName("tagcloud")) + .AddMetadata(ViewComponentTagHelperMetadata.Name, "TagCloud") .Build() }; @@ -133,16 +129,14 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore. var tagHelpers = new[] { - TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly") - .BindAttribute(attribute => - attribute - .Name("Foo") - .TypeName("System.Collections.Generic.Dictionary") - .PropertyName("Tags") - .AsDictionary("foo-", "System.Int32")) - .TagMatchingRule(rule => - rule.RequireTagName("tagcloud")) - .AddMetadata(ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey, "TagCloud") + TagHelperDescriptorBuilder.Create(ViewComponentTagHelperConventions.Kind, "TestTagHelper", "TestAssembly") + .BindAttribute(attribute => attribute + .Name("Foo") + .TypeName("System.Collections.Generic.Dictionary") + .PropertyName("Tags") + .AsDictionary("foo-", "System.Int32")) + .TagMatchingRule(rule => rule.RequireTagName("tagcloud")) + .AddMetadata(ViewComponentTagHelperMetadata.Name, "TagCloud") .Build() }; @@ -207,6 +201,7 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore. var tagHelpers = new[] { TagHelperDescriptorBuilder.Create("PTestTagHelper", "TestAssembly") + .TypeName("PTestTagHelper") .BindAttribute(attribute => attribute .Name("Foo") @@ -214,15 +209,13 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore. .TagMatchingRule(rule => rule.RequireTagName("p")) .Build(), - TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly") - .BindAttribute(attribute => - attribute - .Name("Foo") - .TypeName("System.Int32") - .PropertyName("Foo")) - .TagMatchingRule(rule => - rule.RequireTagName("tagcloud")) - .AddMetadata(ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey, "TagCloud") + TagHelperDescriptorBuilder.Create(ViewComponentTagHelperConventions.Kind, "TestTagHelper", "TestAssembly") + .BindAttribute(attribute => attribute + .Name("Foo") + .TypeName("System.Int32") + .PropertyName("Foo")) + .TagMatchingRule(rule => rule.RequireTagName("tagcloud")) + .AddMetadata(ViewComponentTagHelperMetadata.Name, "TagCloud") .Build() }; diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/BoundAttributeDescriptorExtensionsTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/BoundAttributeDescriptorExtensionsTest.cs index 0eba3ee16d..c3e1c18ecf 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/BoundAttributeDescriptorExtensionsTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/BoundAttributeDescriptorExtensionsTest.cs @@ -12,11 +12,17 @@ namespace Microsoft.AspNetCore.Razor.Language { // Arrange var expectedPropertyName = "IntProperty"; - var descriptor = BoundAttributeDescriptorBuilder.Create("TestTagHelper") + + var tagHelperBuilder = new DefaultTagHelperDescriptorBuilder(TagHelperConventions.DefaultKind, "TestTagHelper", "Test"); + tagHelperBuilder.TypeName("TestTagHelper"); + + var builder = new DefaultBoundAttributeDescriptorBuilder(tagHelperBuilder, TagHelperConventions.DefaultKind); + builder .Name("test") .PropertyName(expectedPropertyName) - .TypeName(typeof(int).FullName) - .Build(); + .TypeName(typeof(int).FullName); + + var descriptor = builder.Build(); // Act var propertyName = descriptor.GetPropertyName(); @@ -29,10 +35,15 @@ namespace Microsoft.AspNetCore.Razor.Language public void GetPropertyName_ReturnsNullIfNoPropertyName() { // Arrange - var descriptor = BoundAttributeDescriptorBuilder.Create("TestTagHelper") + var tagHelperBuilder = new DefaultTagHelperDescriptorBuilder(TagHelperConventions.DefaultKind, "TestTagHelper", "Test"); + tagHelperBuilder.TypeName("TestTagHelper"); + + var builder = new DefaultBoundAttributeDescriptorBuilder(tagHelperBuilder, TagHelperConventions.DefaultKind); + builder .Name("test") - .TypeName(typeof(int).FullName) - .Build(); + .TypeName(typeof(int).FullName); + + var descriptor = builder.Build(); // Act var propertyName = descriptor.GetPropertyName(); @@ -42,14 +53,19 @@ namespace Microsoft.AspNetCore.Razor.Language } [Fact] - public void IsDefaultKind_ReturnsTrueIfFromDefaultBuilder() + public void IsDefaultKind_ReturnsTrue_IfKindIsDefault() { // Arrange - var descriptor = BoundAttributeDescriptorBuilder.Create("TestTagHelper") + var tagHelperBuilder = new DefaultTagHelperDescriptorBuilder(TagHelperConventions.DefaultKind, "TestTagHelper", "Test"); + tagHelperBuilder.TypeName("TestTagHelper"); + + var builder = new DefaultBoundAttributeDescriptorBuilder(tagHelperBuilder, TagHelperConventions.DefaultKind); + builder .Name("test") .PropertyName("IntProperty") - .TypeName(typeof(int).FullName) - .Build(); + .TypeName(typeof(int).FullName); + + var descriptor = builder.Build(); // Act var isDefault = descriptor.IsDefaultKind(); @@ -59,10 +75,19 @@ namespace Microsoft.AspNetCore.Razor.Language } [Fact] - public void IsDefaultKind_ReturnsFalseIfFromCustomBuilder() + public void IsDefaultKind_ReturnsFalse_IfKindIsNotDefault() { // Arrange - var descriptor = new CustomBoundAttributeDescriptor(); + var tagHelperBuilder = new DefaultTagHelperDescriptorBuilder("other-kind", "TestTagHelper", "Test"); + tagHelperBuilder.TypeName("TestTagHelper"); + + var builder = new DefaultBoundAttributeDescriptorBuilder(tagHelperBuilder, "other-kind"); + builder + .Name("test") + .PropertyName("IntProperty") + .TypeName(typeof(int).FullName); + + var descriptor = builder.Build(); // Act var isDefault = descriptor.IsDefaultKind(); @@ -70,12 +95,5 @@ namespace Microsoft.AspNetCore.Razor.Language // Assert Assert.False(isDefault); } - - private class CustomBoundAttributeDescriptor : BoundAttributeDescriptor - { - public CustomBoundAttributeDescriptor() : base("custom") - { - } - } } } diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/DesignTimeTagHelperWriterTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/DesignTimeTagHelperWriterTest.cs index 035c77834f..ddea3bcecf 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/DesignTimeTagHelperWriterTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/DesignTimeTagHelperWriterTest.cs @@ -247,6 +247,7 @@ __InputTagHelper.FooProp[""bound""] = 42; IEnumerable> attributes = null) { var builder = TagHelperDescriptorBuilder.Create(typeName, assemblyName); + builder.TypeName(typeName); if (attributes != null) { diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/RuntimeTagHelperWriterTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/RuntimeTagHelperWriterTest.cs index d0da4dcb11..b49fd37571 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/RuntimeTagHelperWriterTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/CodeGeneration/RuntimeTagHelperWriterTest.cs @@ -483,6 +483,7 @@ __tagHelperExecutionContext.AddTagHelperAttribute(""foo-bound"", __InputTagHelpe IEnumerable> attributes = null) { var builder = TagHelperDescriptorBuilder.Create(typeName, assemblyName); + builder.TypeName(typeName); if (attributes != null) { diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/BoundAttributeDescriptorBuilderTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultBoundAttributeDescriptorBuilderTest.cs similarity index 55% rename from test/Microsoft.AspNetCore.Razor.Language.Test/BoundAttributeDescriptorBuilderTest.cs rename to test/Microsoft.AspNetCore.Razor.Language.Test/DefaultBoundAttributeDescriptorBuilderTest.cs index ff3a3d11bd..52317aa157 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/BoundAttributeDescriptorBuilderTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultBoundAttributeDescriptorBuilderTest.cs @@ -5,17 +5,21 @@ using Xunit; namespace Microsoft.AspNetCore.Razor.Language { - public class BoundAttributeDescriptorBuilderTest + public class DefaultBoundAttributeDescriptorBuilderTest { [Fact] public void DisplayName_SetsDescriptorsDisplayName() { // Arrange var expectedDisplayName = "ExpectedDisplayName"; - var builder = BoundAttributeDescriptorBuilder.Create("TestTagHelper"); + + var tagHelperBuilder = new DefaultTagHelperDescriptorBuilder(TagHelperConventions.DefaultKind, "TestTagHelper", "Test"); + + var builder = new DefaultBoundAttributeDescriptorBuilder(tagHelperBuilder, TagHelperConventions.DefaultKind); + builder.DisplayName(expectedDisplayName); // Act - var descriptor = builder.DisplayName(expectedDisplayName).Build(); + var descriptor = builder.Build(); // Assert Assert.Equal(expectedDisplayName, descriptor.DisplayName); @@ -25,7 +29,11 @@ namespace Microsoft.AspNetCore.Razor.Language public void DisplayName_DefaultsToPropertyLookingDisplayName() { // Arrange - var builder = BoundAttributeDescriptorBuilder.Create("TestTagHelper") + var tagHelperBuilder = new DefaultTagHelperDescriptorBuilder(TagHelperConventions.DefaultKind, "TestTagHelper", "Test"); + tagHelperBuilder.TypeName("TestTagHelper"); + + var builder = new DefaultBoundAttributeDescriptorBuilder(tagHelperBuilder, TagHelperConventions.DefaultKind); + builder .TypeName(typeof(int).FullName) .PropertyName("SomeProperty"); diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorIntermediateNodeLoweringPhaseIntegrationTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorIntermediateNodeLoweringPhaseIntegrationTest.cs index 6024fa1bdb..accd49fd3c 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorIntermediateNodeLoweringPhaseIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorIntermediateNodeLoweringPhaseIntegrationTest.cs @@ -476,6 +476,7 @@ namespace Microsoft.AspNetCore.Razor.Language IEnumerable> attributes = null) { var builder = TagHelperDescriptorBuilder.Create(typeName, assemblyName); + builder.TypeName(typeName); if (attributes != null) { diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorTagHelperBinderPhaseTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorTagHelperBinderPhaseTest.cs index c264bbf92b..78c89df6df 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorTagHelperBinderPhaseTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorTagHelperBinderPhaseTest.cs @@ -160,11 +160,11 @@ namespace Microsoft.AspNetCore.Razor.Language { CreateTagHelperDescriptor( tagName: "form", - typeName: null, + typeName: "TestFormTagHelper", assemblyName: "TestAssembly"), CreateTagHelperDescriptor( tagName: "input", - typeName: null, + typeName: "TestInputTagHelper", assemblyName: "TestAssembly"), }); }); @@ -201,7 +201,7 @@ namespace Microsoft.AspNetCore.Razor.Language tagName: "form", typeName: "TestFormTagHelper", assemblyName: "TestAssembly", - ruleBuilders: new Action[] + ruleBuilders: new Action[] { ruleBuilder => ruleBuilder .RequireAttribute(attribute => attribute @@ -254,7 +254,7 @@ namespace Microsoft.AspNetCore.Razor.Language tagName: "form", typeName: "TestFormTagHelper", assemblyName: "TestAssembly", - ruleBuilders: new Action[] + ruleBuilders: new Action[] { ruleBuilder => ruleBuilder .RequireAttribute(attribute => attribute @@ -415,11 +415,11 @@ namespace Microsoft.AspNetCore.Razor.Language { CreateTagHelperDescriptor( tagName: "form", - typeName: null, + typeName: "TestFormTagHelper", assemblyName: "TestAssembly"), CreateTagHelperDescriptor( tagName: "input", - typeName: null, + typeName: "TestInputTagHelper", assemblyName: "TestAssembly"), }); }); @@ -1323,7 +1323,7 @@ namespace Microsoft.AspNetCore.Razor.Language var expectedErrorMessage = string.Format( "Invalid tag helper directive look up text '{0}'. The correct look up text " + - "format is: \"typeName, assemblyName\".", + "format is: \"name, assemblyName\".", directiveText); var expectedError = RazorDiagnostic.Create( @@ -1346,28 +1346,16 @@ namespace Microsoft.AspNetCore.Razor.Language private static TagHelperDescriptor CreatePrefixedValidPlainDescriptor(string prefix) { return Valid_PlainTagHelperDescriptor; - //return new TagHelperDescriptor(Valid_PlainTagHelperDescriptor) - //{ - // Prefix = prefix, - //}; } private static TagHelperDescriptor CreatePrefixedValidInheritedDescriptor(string prefix) { return Valid_InheritedTagHelperDescriptor; - //return new TagHelperDescriptor(Valid_InheritedTagHelperDescriptor) - //{ - // Prefix = prefix, - //}; } private static TagHelperDescriptor CreatePrefixedStringDescriptor(string prefix) { return String_TagHelperDescriptor; - //return new TagHelperDescriptor(String_TagHelperDescriptor) - //{ - // Prefix = prefix, - //}; } private static TagHelperDirectiveDescriptor CreateTagHelperDirectiveDescriptor( @@ -1400,9 +1388,10 @@ namespace Microsoft.AspNetCore.Razor.Language string typeName, string assemblyName, IEnumerable> attributes = null, - IEnumerable> ruleBuilders = null) + IEnumerable> ruleBuilders = null) { var builder = TagHelperDescriptorBuilder.Create(typeName, assemblyName); + builder.TypeName(typeName); if (attributes != null) { diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperRequiredAttributeDescriptorBuilderTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRequiredAttributeDescriptorBuilderTest.cs similarity index 74% rename from test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperRequiredAttributeDescriptorBuilderTest.cs rename to test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRequiredAttributeDescriptorBuilderTest.cs index 5b81a9c9a0..f847f6ae3c 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperRequiredAttributeDescriptorBuilderTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRequiredAttributeDescriptorBuilderTest.cs @@ -5,18 +5,20 @@ using Xunit; namespace Microsoft.AspNetCore.Razor.Language { - public class TagHelperRequiredAttributeDescriptorBuilderTest + public class DefaultRequiredAttributeDescriptorBuilderTest { [Fact] public void Build_DisplayNameIsName_NameComparisonFullMatch() { // Arrange - var descriptorBuilder = RequiredAttributeDescriptorBuilder.Create() + var builder = new DefaultRequiredAttributeDescriptorBuilder(); + + builder .Name("asp-action") .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.FullMatch); // Act - var descriptor = descriptorBuilder.Build(); + var descriptor = builder.Build(); // Assert Assert.Equal("asp-action", descriptor.DisplayName); @@ -26,12 +28,14 @@ namespace Microsoft.AspNetCore.Razor.Language public void Build_DisplayNameIsNameWithDots_NameComparisonPrefixMatch() { // Arrange - var descriptorBuilder = RequiredAttributeDescriptorBuilder.Create() + var builder = new DefaultRequiredAttributeDescriptorBuilder(); + + builder .Name("asp-route-") .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch); // Act - var descriptor = descriptorBuilder.Build(); + var descriptor = builder.Build(); // Assert Assert.Equal("asp-route-...", descriptor.DisplayName); diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/PreallocatedAttributeTargetExtensionTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/PreallocatedAttributeTargetExtensionTest.cs index d6e1c28815..3146c34efc 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/PreallocatedAttributeTargetExtensionTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Extensions/PreallocatedAttributeTargetExtensionTest.cs @@ -135,12 +135,17 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions Writer = new CSharpCodeWriter() }; - var descriptor = BoundAttributeDescriptorBuilder - .Create("FooTagHelper") + var tagHelperBuilder = new DefaultTagHelperDescriptorBuilder(TagHelperConventions.DefaultKind, "FooTagHelper", "Test"); + tagHelperBuilder.TypeName("FooTagHelper"); + + var builder = new DefaultBoundAttributeDescriptorBuilder(tagHelperBuilder, TagHelperConventions.DefaultKind); + + builder .Name("Foo") .TypeName("System.String") - .PropertyName("FooProp") - .Build(); + .PropertyName("FooProp"); + + var descriptor = builder.Build(); var node = new SetPreallocatedTagHelperPropertyIntermediateNode() { @@ -174,13 +179,18 @@ __tagHelperExecutionContext.AddTagHelperAttribute(_tagHelper1); TagHelperRenderingContext = new TagHelperRenderingContext() }; - var descriptor = BoundAttributeDescriptorBuilder - .Create("FooTagHelper") + var tagHelperBuilder = new DefaultTagHelperDescriptorBuilder(TagHelperConventions.DefaultKind, "FooTagHelper", "Test"); + tagHelperBuilder.TypeName("FooTagHelper"); + + var builder = new DefaultBoundAttributeDescriptorBuilder(tagHelperBuilder, TagHelperConventions.DefaultKind); + + builder .Name("Foo") .TypeName("System.Collections.Generic.Dictionary") .AsDictionary("pre-", "System.String") - .PropertyName("FooProp") - .Build(); + .PropertyName("FooProp"); + + var descriptor = builder.Build(); var node = new SetPreallocatedTagHelperPropertyIntermediateNode() { diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/IntegrationTests/TagHelpersIntegrationTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/IntegrationTests/TagHelpersIntegrationTest.cs index 9e7b370eee..3016cd87d5 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/IntegrationTests/TagHelpersIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/IntegrationTests/TagHelpersIntegrationTest.cs @@ -104,6 +104,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests IEnumerable> attributes = null) { var builder = TagHelperDescriptorBuilder.Create(typeName, assemblyName); + builder.TypeName(typeName); if (attributes != null) { diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/IntegrationTests/TestTagHelperDescriptors.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/IntegrationTests/TestTagHelperDescriptors.cs index 14ae56a1af..47000a154a 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/IntegrationTests/TestTagHelperDescriptors.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/IntegrationTests/TestTagHelperDescriptors.cs @@ -59,7 +59,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests tagName: "a", typeName: "TestNamespace.ATagHelper", assemblyName: "TestAssembly", - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder .RequireAttribute(attribute => attribute @@ -72,7 +72,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests tagName: "a", typeName: "TestNamespace.ATagHelperMultipleSelectors", assemblyName: "TestAssembly", - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder .RequireAttribute(attribute => attribute @@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests { builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", inputTypePropertyInfo), }, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder .RequireAttribute(attribute => attribute @@ -111,7 +111,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests { builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", inputTypePropertyInfo), }, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder .RequireAttribute(attribute => attribute @@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests tagName: "*", typeName: "TestNamespace.CatchAllTagHelper", assemblyName: "TestAssembly", - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder .RequireAttribute(attribute => attribute @@ -135,7 +135,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests tagName: "*", typeName: "TestNamespace.CatchAllTagHelper2", assemblyName: "TestAssembly", - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder .RequireAttribute(attribute => attribute @@ -195,7 +195,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests builder => builder .Name("[item]") .PropertyName("ListItems") - .TypeName(typeof(List).FullName), + .TypeName("System.Collections.Generic.List"), builder => builder .Name("[(item)]") .PropertyName("ArrayItems") @@ -217,7 +217,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests .PropertyName("StringProperty2") .TypeName(typeof(string).FullName), }, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder.RequireAttribute(attribute => attribute.Name("bound")), }), @@ -242,7 +242,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests .PropertyName("BoundRequiredString") .TypeName(typeof(string).FullName), }, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder.RequireAttribute(attribute => attribute.Name("catchall-unbound-required")), }), @@ -261,7 +261,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests .PropertyName("BoundString") .TypeName(typeof(string).FullName), }, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder .RequireAttribute(attribute => attribute.Name("input-bound-required-string")) @@ -309,7 +309,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", typePropertyInfo), builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "checked", checkedPropertyInfo), }, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder.RequireAttribute(attribute => attribute.Name("type")), builder => builder.RequireAttribute(attribute => attribute.Name("checked")) @@ -323,7 +323,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", typePropertyInfo), builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "checked", checkedPropertyInfo), }, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder.RequireAttribute(attribute => attribute.Name("type")), builder => builder.RequireAttribute(attribute => attribute.Name("checked")) @@ -344,7 +344,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests tagName: "p", typeName: "TestNamespace.PTagHelper", assemblyName: "TestAssembly", - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder.RequireAttribute(attribute => attribute.Name("class")), }), @@ -356,7 +356,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests { builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", inputTypePropertyInfo), }, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder.RequireAttribute(attribute => attribute.Name("type")), }), @@ -369,7 +369,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", inputTypePropertyInfo), builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "checked", inputCheckedPropertyInfo), }, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder .RequireAttribute(attribute => attribute.Name("type")) @@ -379,7 +379,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests tagName: "*", typeName: "TestNamespace.CatchAllTagHelper", assemblyName: "TestAssembly", - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder.RequireAttribute(attribute => attribute.Name("catchAll")), }), @@ -480,7 +480,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests { builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "age", pAgePropertyInfo), }, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder.RequireTagStructure(TagStructure.NormalOrSelfClosing) }), @@ -492,7 +492,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests { builder => BuildBoundAttributeDescriptorFromPropertyInfo(builder, "type", inputTypePropertyInfo), }, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder.RequireTagStructure(TagStructure.WithoutEndTag) }), @@ -514,9 +514,10 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests string typeName, string assemblyName, IEnumerable> attributes = null, - IEnumerable> ruleBuilders = null) + IEnumerable> ruleBuilders = null) { var builder = TagHelperDescriptorBuilder.Create(typeName, assemblyName); + builder.TypeName(typeName); if (attributes != null) { @@ -530,7 +531,8 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests { foreach (var ruleBuilder in ruleBuilders) { - builder.TagMatchingRule(innerRuleBuilder => { + builder.TagMatchingRule(innerRuleBuilder => + { innerRuleBuilder.RequireTagName(tagName); ruleBuilder(innerRuleBuilder); }); diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/TagHelperParseTreeRewriterTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/TagHelperParseTreeRewriterTest.cs index 3e6886ffae..dea7f61983 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/TagHelperParseTreeRewriterTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/Legacy/TagHelperParseTreeRewriterTest.cs @@ -1165,7 +1165,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy "InputTagHelper1", "InputTagHelper2", "input", - nameof(TagMatchingRule.TagStructure)), + nameof(TagMatchingRuleDescriptor.TagStructure)), absoluteIndex: 0, lineIndex: 0, columnIndex: 0, diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperBinderTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperBinderTest.cs index 0dc5d70f2e..d755ca1b7c 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperBinderTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperBinderTest.cs @@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Razor.Language Assert.Equal("body", bindingResult.ParentTagName); Assert.Equal(expectedAttributes, bindingResult.Attributes); Assert.Equal("th:", bindingResult.TagHelperPrefix); - Assert.Equal(divTagHelper.TagMatchingRules, bindingResult.GetBoundRules(divTagHelper), TagMatchingRuleComparer.CaseSensitive); + Assert.Equal(divTagHelper.TagMatchingRules, bindingResult.GetBoundRules(divTagHelper), TagMatchingRuleDescriptorComparer.CaseSensitive); } public static TheoryData RequiredParentData diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperDescriptorExtensionsTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperDescriptorExtensionsTest.cs index ac55dff8ac..0940661058 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperDescriptorExtensionsTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperDescriptorExtensionsTest.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Razor.Language { // Arrange var expectedTypeName = "TestTagHelper"; - var descriptor = TagHelperDescriptorBuilder.Create(expectedTypeName, "TestAssembly").Build(); + var descriptor = TagHelperDescriptorBuilder.Create(expectedTypeName, "TestAssembly").TypeName(expectedTypeName).Build(); // Act var typeName = descriptor.GetTypeName(); @@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Razor.Language public void GetTypeName_ReturnsNullIfNoTypeName() { // Arrange - var descriptor = new CustomTagHelperDescriptor(); + var descriptor = TagHelperDescriptorBuilder.Create("Test", "TestAssembly").Build(); // Act var typeName = descriptor.GetTypeName(); @@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Razor.Language } [Fact] - public void IsDefaultKind_ReturnsTrueIfFromDefaultBuilder() + public void IsDefaultKind_ReturnsTrue_IfKindIsDefault() { // Arrange var descriptor = TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly").Build(); @@ -49,10 +49,10 @@ namespace Microsoft.AspNetCore.Razor.Language } [Fact] - public void IsDefaultKind_ReturnsFalseIfFromCustomBuilder() + public void IsDefaultKind_ReturnsFalse_IfKindIsNotDefault() { // Arrange - var descriptor = new CustomTagHelperDescriptor(); + var descriptor = TagHelperDescriptorBuilder.Create("other-kind", "TestTagHelper", "TestAssembly").Build(); // Act var isDefault = descriptor.IsDefaultKind(); @@ -60,13 +60,5 @@ namespace Microsoft.AspNetCore.Razor.Language // Assert Assert.False(isDefault); } - - private class CustomTagHelperDescriptor : TagHelperDescriptor - { - public CustomTagHelperDescriptor() : base("custom") - { - Metadata = new Dictionary(); - } - } } } diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperRequiredAttributeDescriptorTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperMatchingConventionsTest.cs similarity index 69% rename from test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperRequiredAttributeDescriptorTest.cs rename to test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperMatchingConventionsTest.cs index eedb969b1e..7a1fc6c1e3 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperRequiredAttributeDescriptorTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/TagHelperMatchingConventionsTest.cs @@ -1,138 +1,128 @@ // 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 Xunit; namespace Microsoft.AspNetCore.Razor.Language { - public class TagHelperRequiredAttributeDescriptorTest + public class TagHelperMatchingConventionsTest { public static TheoryData RequiredAttributeDescriptorData { get { // requiredAttributeDescriptor, attributeName, attributeValue, expectedResult - return new TheoryData + return new TheoryData, string, string, bool> { { - RequiredAttributeDescriptorBuilder.Create().Name("key").Build(), + builder => builder.Name("key"), "KeY", "value", true }, { - RequiredAttributeDescriptorBuilder.Create().Name("key").Build(), + builder => builder.Name("key"), "keys", "value", false }, { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("route-") - .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch) - .Build(), + .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch), "ROUTE-area", "manage", true }, { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("route-") - .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch) - .Build(), + .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch), "routearea", "manage", false }, { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("route-") - .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch) - .Build(), + .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch), "route-", "manage", false }, { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("key") - .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.FullMatch) - .Build(), + .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.FullMatch), "KeY", "value", true }, { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("key") - .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.FullMatch) - .Build(), + .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.FullMatch), "keys", "value", false }, { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("key") .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.FullMatch) .Value("value") - .ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode.FullMatch) - .Build(), + .ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode.FullMatch), "key", "value", true }, { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("key") .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.FullMatch) .Value("value") - .ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode.FullMatch) - .Build(), + .ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode.FullMatch), "key", "Value", false }, { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("class") .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.FullMatch) .Value("btn") - .ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode.PrefixMatch) - .Build(), + .ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode.PrefixMatch), "class", "btn btn-success", true }, { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("class") .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.FullMatch) .Value("btn") - .ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode.PrefixMatch) - .Build(), + .ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode.PrefixMatch), "class", "BTN btn-success", false }, { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("href") .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.FullMatch) .Value("#navigate") - .ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode.SuffixMatch) - .Build(), + .ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode.SuffixMatch), "href", "/home/index#navigate", true }, { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("href") .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.FullMatch) .Value("#navigate") - .ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode.SuffixMatch) - .Build(), + .ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode.SuffixMatch), "href", "/home/index#NAVigate", false @@ -144,13 +134,20 @@ namespace Microsoft.AspNetCore.Razor.Language [Theory] [MemberData(nameof(RequiredAttributeDescriptorData))] public void Matches_ReturnsExpectedResult( - object requiredAttributeDescriptor, + Action configure, string attributeName, string attributeValue, bool expectedResult) { + // Arrange + + var builder = new DefaultRequiredAttributeDescriptorBuilder(); + configure(builder); + + var requiredAttibute = builder.Build(); + // Act - var result = TagHelperMatchingConventions.SatisfiesRequiredAttribute(attributeName, attributeValue, (RequiredAttributeDescriptor)requiredAttributeDescriptor); + var result = TagHelperMatchingConventions.SatisfiesRequiredAttribute(attributeName, attributeValue, requiredAttibute); // Assert Assert.Equal(expectedResult, result); diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/SymbolBoundAttributes_DesignTime.diagnostics.txt b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/SymbolBoundAttributes_DesignTime.diagnostics.txt index 54ed3b15e0..1ee160ff70 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/SymbolBoundAttributes_DesignTime.diagnostics.txt +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/SymbolBoundAttributes_DesignTime.diagnostics.txt @@ -1,5 +1,5 @@ -(0,0): Error RZ3003: Invalid tag helper bound property 'TestNamespace.CatchAllTagHelper.ListItems'. Tag helpers cannot bind to HTML attributes with name '[item]' because the name contains a '[' character. -(0,0): Error RZ3003: Invalid tag helper bound property 'TestNamespace.CatchAllTagHelper.ListItems'. Tag helpers cannot bind to HTML attributes with name '[item]' because the name contains a ']' character. -(0,0): Error RZ3003: Invalid tag helper bound property 'TestNamespace.CatchAllTagHelper.ArrayItems'. Tag helpers cannot bind to HTML attributes with name '[(item)]' because the name contains a '[' character. -(0,0): Error RZ3003: Invalid tag helper bound property 'TestNamespace.CatchAllTagHelper.ArrayItems'. Tag helpers cannot bind to HTML attributes with name '[(item)]' because the name contains a ']' character. -(0,0): Error RZ3003: Invalid tag helper bound property 'TestNamespace.CatchAllTagHelper.StringProperty1'. Tag helpers cannot bind to HTML attributes with name '*something' because the name contains a '*' character. +(0,0): Error RZ3003: Invalid tag helper bound property 'System.Collections.Generic.List TestNamespace.CatchAllTagHelper.ListItems' on tag helper 'TestNamespace.CatchAllTagHelper'. Tag helpers cannot bind to HTML attributes with name '[item]' because the name contains a '[' character. +(0,0): Error RZ3003: Invalid tag helper bound property 'System.Collections.Generic.List TestNamespace.CatchAllTagHelper.ListItems' on tag helper 'TestNamespace.CatchAllTagHelper'. Tag helpers cannot bind to HTML attributes with name '[item]' because the name contains a ']' character. +(0,0): Error RZ3003: Invalid tag helper bound property 'System.String[] TestNamespace.CatchAllTagHelper.ArrayItems' on tag helper 'TestNamespace.CatchAllTagHelper'. Tag helpers cannot bind to HTML attributes with name '[(item)]' because the name contains a '[' character. +(0,0): Error RZ3003: Invalid tag helper bound property 'System.String[] TestNamespace.CatchAllTagHelper.ArrayItems' on tag helper 'TestNamespace.CatchAllTagHelper'. Tag helpers cannot bind to HTML attributes with name '[(item)]' because the name contains a ']' character. +(0,0): Error RZ3003: Invalid tag helper bound property 'string TestNamespace.CatchAllTagHelper.StringProperty1' on tag helper 'TestNamespace.CatchAllTagHelper'. Tag helpers cannot bind to HTML attributes with name '*something' because the name contains a '*' character. diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/SymbolBoundAttributes_Runtime.diagnostics.txt b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/SymbolBoundAttributes_Runtime.diagnostics.txt index 54ed3b15e0..1ee160ff70 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/SymbolBoundAttributes_Runtime.diagnostics.txt +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/SymbolBoundAttributes_Runtime.diagnostics.txt @@ -1,5 +1,5 @@ -(0,0): Error RZ3003: Invalid tag helper bound property 'TestNamespace.CatchAllTagHelper.ListItems'. Tag helpers cannot bind to HTML attributes with name '[item]' because the name contains a '[' character. -(0,0): Error RZ3003: Invalid tag helper bound property 'TestNamespace.CatchAllTagHelper.ListItems'. Tag helpers cannot bind to HTML attributes with name '[item]' because the name contains a ']' character. -(0,0): Error RZ3003: Invalid tag helper bound property 'TestNamespace.CatchAllTagHelper.ArrayItems'. Tag helpers cannot bind to HTML attributes with name '[(item)]' because the name contains a '[' character. -(0,0): Error RZ3003: Invalid tag helper bound property 'TestNamespace.CatchAllTagHelper.ArrayItems'. Tag helpers cannot bind to HTML attributes with name '[(item)]' because the name contains a ']' character. -(0,0): Error RZ3003: Invalid tag helper bound property 'TestNamespace.CatchAllTagHelper.StringProperty1'. Tag helpers cannot bind to HTML attributes with name '*something' because the name contains a '*' character. +(0,0): Error RZ3003: Invalid tag helper bound property 'System.Collections.Generic.List TestNamespace.CatchAllTagHelper.ListItems' on tag helper 'TestNamespace.CatchAllTagHelper'. Tag helpers cannot bind to HTML attributes with name '[item]' because the name contains a '[' character. +(0,0): Error RZ3003: Invalid tag helper bound property 'System.Collections.Generic.List TestNamespace.CatchAllTagHelper.ListItems' on tag helper 'TestNamespace.CatchAllTagHelper'. Tag helpers cannot bind to HTML attributes with name '[item]' because the name contains a ']' character. +(0,0): Error RZ3003: Invalid tag helper bound property 'System.String[] TestNamespace.CatchAllTagHelper.ArrayItems' on tag helper 'TestNamespace.CatchAllTagHelper'. Tag helpers cannot bind to HTML attributes with name '[(item)]' because the name contains a '[' character. +(0,0): Error RZ3003: Invalid tag helper bound property 'System.String[] TestNamespace.CatchAllTagHelper.ArrayItems' on tag helper 'TestNamespace.CatchAllTagHelper'. Tag helpers cannot bind to HTML attributes with name '[(item)]' because the name contains a ']' character. +(0,0): Error RZ3003: Invalid tag helper bound property 'string TestNamespace.CatchAllTagHelper.StringProperty1' on tag helper 'TestNamespace.CatchAllTagHelper'. Tag helpers cannot bind to HTML attributes with name '*something' because the name contains a '*' character. diff --git a/test/Microsoft.CodeAnalysis.Razor.Test/DefaultTagHelperDescriptorFactoryTest.cs b/test/Microsoft.CodeAnalysis.Razor.Test/DefaultTagHelperDescriptorFactoryTest.cs index 3d1ea6ff3a..5c602ed165 100644 --- a/test/Microsoft.CodeAnalysis.Razor.Test/DefaultTagHelperDescriptorFactoryTest.cs +++ b/test/Microsoft.CodeAnalysis.Razor.Test/DefaultTagHelperDescriptorFactoryTest.cs @@ -28,182 +28,165 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces { get { - return new TheoryData + return new TheoryData[]> { { "name,", - new[] + new Action[] { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("name") - .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_CouldNotFindMatchingEndBrace("name,")) - .Build(), + .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_CouldNotFindMatchingEndBrace("name,")), } }, { " ", - new[] + new Action[] { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name(string.Empty) - .AddDiagnostic(AspNetCore.Razor.Language.RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedAttributeNameNullOrWhitespace()) - .Build(), + .AddDiagnostic(AspNetCore.Razor.Language.RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedAttributeNameNullOrWhitespace()), } }, { "n@me", - new[] + new Action[] { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("n@me") - .AddDiagnostic(AspNetCore.Razor.Language.RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedAttributeName("n@me", '@')) - .Build(), + .AddDiagnostic(AspNetCore.Razor.Language.RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedAttributeName("n@me", '@')), } }, { "name extra", - new[] + new Action[] { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("name") - .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_InvalidRequiredAttributeCharacter('e', "name extra")) - .Build(), + .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_InvalidRequiredAttributeCharacter('e', "name extra")), } }, { "[[ ", - new[] + new Action[] { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("[") - .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_CouldNotFindMatchingEndBrace("[[ ")) - .Build(), + .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_CouldNotFindMatchingEndBrace("[[ ")), } }, { "[ ", - new[] + new Action[] { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("") - .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_CouldNotFindMatchingEndBrace("[ ")) - .Build(), + .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_CouldNotFindMatchingEndBrace("[ ")), } }, { "[name='unended]", - new[] + new Action[] { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("name") .ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode.FullMatch) - .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_InvalidRequiredAttributeMismatchedQuotes('\'', "[name='unended]")) - .Build(), + .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_InvalidRequiredAttributeMismatchedQuotes('\'', "[name='unended]")), } }, { "[name='unended", - new[] + new Action[] { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("name") .ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode.FullMatch) - .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_InvalidRequiredAttributeMismatchedQuotes('\'', "[name='unended")) - .Build(), + .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_InvalidRequiredAttributeMismatchedQuotes('\'', "[name='unended")), } }, { "[name", - new[] + new Action[] { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("name") - .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_CouldNotFindMatchingEndBrace("[name")) - .Build(), + .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_CouldNotFindMatchingEndBrace("[name")), } }, { "[ ]", - new[] + new Action[] { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name(string.Empty) - .AddDiagnostic(AspNetCore.Razor.Language.RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedAttributeNameNullOrWhitespace()) - .Build(), + .AddDiagnostic(AspNetCore.Razor.Language.RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedAttributeNameNullOrWhitespace()), } }, { "[n@me]", - new[] + new Action[] { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("n@me") - .AddDiagnostic(AspNetCore.Razor.Language.RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedAttributeName("n@me", '@')) - .Build(), + .AddDiagnostic(AspNetCore.Razor.Language.RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedAttributeName("n@me", '@')), } }, { "[name@]", - new[] + new Action[] { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("name@") - .AddDiagnostic(AspNetCore.Razor.Language.RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedAttributeName("name@", '@')) - .Build(), + .AddDiagnostic(AspNetCore.Razor.Language.RazorDiagnosticFactory.CreateTagHelper_InvalidTargetedAttributeName("name@", '@')), } }, { "[name^]", - new[] + new Action[] { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("name") - .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_PartialRequiredAttributeOperator('^', "[name^]")) - .Build(), + .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_PartialRequiredAttributeOperator('^', "[name^]")), } }, { "[name='value'", - new[] + new Action[] { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("name") .Value("value") .ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode.FullMatch) - .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_CouldNotFindMatchingEndBrace("[name='value'")) - .Build(), + .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_CouldNotFindMatchingEndBrace("[name='value'")), } }, { "[name ", - new[] + new Action[] { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("name") - .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_CouldNotFindMatchingEndBrace("[name ")) - .Build(), + .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_CouldNotFindMatchingEndBrace("[name ")), } }, { "[name extra]", - new[] + new Action[] { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("name") - .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_InvalidRequiredAttributeOperator('e', "[name extra]")) - .Build(), + .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_InvalidRequiredAttributeOperator('e', "[name extra]")), } }, { "[name=value ", - new[] + new Action[] { - RequiredAttributeDescriptorBuilder.Create() + builder => builder .Name("name") .Value("value") .ValueComparisonMode(RequiredAttributeDescriptor.ValueComparisonMode.FullMatch) - .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_CouldNotFindMatchingEndBrace("[name=value ")) - .Build(), + .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_CouldNotFindMatchingEndBrace("[name=value ")), } }, }; @@ -214,39 +197,47 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces [MemberData(nameof(RequiredAttributeParserErrorData))] public void RequiredAttributeParser_ParsesRequiredAttributesAndLogsDiagnosticsCorrectly( string requiredAttributes, - IEnumerable expectedDescriptors) + IEnumerable> configureBuilders) { // Arrange - var ruleBuilder = TagMatchingRuleBuilder.Create(); + var ruleBuilder = new DefaultTagMatchingRuleDescriptorBuilder(); + + var expectedRules = new List(); + foreach (var configureBuilder in configureBuilders) + { + var builder = new DefaultRequiredAttributeDescriptorBuilder(); + configureBuilder(builder); + + expectedRules.Add(builder.Build()); + } // Act RequiredAttributeParser.AddRequiredAttributes(requiredAttributes, ruleBuilder); // Assert var descriptors = ruleBuilder.Build().Attributes; - Assert.Equal(expectedDescriptors, descriptors, RequiredAttributeDescriptorComparer.CaseSensitive); + Assert.Equal(expectedRules, descriptors, RequiredAttributeDescriptorComparer.CaseSensitive); } public static TheoryData RequiredAttributeParserData { get { - Func plain = - (name, nameComparison) => RequiredAttributeDescriptorBuilder.Create() + Func> plain = + (name, nameComparison) => (builder) => builder .Name(name) - .NameComparisonMode(nameComparison) - .Build(); - Func css = - (name, value, valueComparison) => RequiredAttributeDescriptorBuilder.Create() + .NameComparisonMode(nameComparison); + + Func> css = + (name, value, valueComparison) => (builder) => builder .Name(name) .Value(value) - .ValueComparisonMode(valueComparison) - .Build(); + .ValueComparisonMode(valueComparison); - return new TheoryData> + return new TheoryData>> { - { null, Enumerable.Empty() }, - { string.Empty, Enumerable.Empty() }, + { null, Enumerable.Empty>() }, + { string.Empty, Enumerable.Empty>() }, { "name", new[] { plain("name", RequiredAttributeDescriptor.NameComparisonMode.FullMatch) } }, { "name-*", new[] { plain("name-", RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch) } }, { " name-* ", new[] { plain("name-", RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch) } }, @@ -300,17 +291,26 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces [MemberData(nameof(RequiredAttributeParserData))] public void RequiredAttributeParser_ParsesRequiredAttributesCorrectly( string requiredAttributes, - IEnumerable expectedDescriptors) + IEnumerable> configureBuilders) { // Arrange - var ruleBuilder = TagMatchingRuleBuilder.Create(); + var ruleBuilder = new DefaultTagMatchingRuleDescriptorBuilder(); + + var expectedRules = new List(); + foreach (var configureBuilder in configureBuilders) + { + var builder = new DefaultRequiredAttributeDescriptorBuilder(); + configureBuilder(builder); + + expectedRules.Add(builder.Build()); + } // Act RequiredAttributeParser.AddRequiredAttributes(requiredAttributes, ruleBuilder); // Assert var descriptors = ruleBuilder.Build().Attributes; - Assert.Equal(expectedDescriptors, descriptors, RequiredAttributeDescriptorComparer.CaseSensitive); + Assert.Equal(expectedRules, descriptors, RequiredAttributeDescriptorComparer.CaseSensitive); } public static TheoryData IsEnumData @@ -323,6 +323,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces { typeof(EnumTagHelper), TagHelperDescriptorBuilder.Create(typeof(EnumTagHelper).FullName, AssemblyName) + .TypeName(typeof(EnumTagHelper).FullName) .TagMatchingRule(ruleBuilder => ruleBuilder.RequireTagName("enum")) .BindAttribute(builder => builder @@ -340,6 +341,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces { typeof(MultiEnumTagHelper), TagHelperDescriptorBuilder.Create(typeof(MultiEnumTagHelper).FullName, AssemblyName) + .TypeName(typeof(MultiEnumTagHelper).FullName) .TagMatchingRule(ruleBuilder => ruleBuilder.RequireTagName("p")) .TagMatchingRule(ruleBuilder => ruleBuilder.RequireTagName("input")) .BindAttribute(builder => @@ -358,6 +360,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces { typeof(NestedEnumTagHelper), TagHelperDescriptorBuilder.Create(typeof(NestedEnumTagHelper).FullName, AssemblyName) + .TypeName(typeof(NestedEnumTagHelper).FullName) .TagMatchingRule(ruleBuilder => ruleBuilder.RequireTagName("nested-enum")) .BindAttribute(builder => builder @@ -409,12 +412,14 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces { typeof(RequiredParentTagHelper), TagHelperDescriptorBuilder.Create(typeof(RequiredParentTagHelper).FullName, AssemblyName) + .TypeName(typeof(RequiredParentTagHelper).FullName) .TagMatchingRule(builder => builder.RequireTagName("input").RequireParentTag("div")) .Build() }, { typeof(MultiSpecifiedRequiredParentTagHelper), TagHelperDescriptorBuilder.Create(typeof(MultiSpecifiedRequiredParentTagHelper).FullName, AssemblyName) + .TypeName(typeof(MultiSpecifiedRequiredParentTagHelper).FullName) .TagMatchingRule(builder => builder.RequireTagName("p").RequireParentTag("div")) .TagMatchingRule(builder => builder.RequireTagName("input").RequireParentTag("section")) .Build() @@ -422,6 +427,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces { typeof(MultiWithUnspecifiedRequiredParentTagHelper), TagHelperDescriptorBuilder.Create(typeof(MultiWithUnspecifiedRequiredParentTagHelper).FullName, AssemblyName) + .TypeName(typeof(MultiWithUnspecifiedRequiredParentTagHelper).FullName) .TagMatchingRule(builder => builder.RequireTagName("p")) .TagMatchingRule(builder => builder.RequireTagName("input").RequireParentTag("div")) .Build() @@ -457,6 +463,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces { typeof(RestrictChildrenTagHelper), TagHelperDescriptorBuilder.Create(typeof(RestrictChildrenTagHelper).FullName, AssemblyName) + .TypeName(typeof(RestrictChildrenTagHelper).FullName) .TagMatchingRule(builder => builder.RequireTagName("restrict-children")) .AllowChildTag("p") .Build() @@ -464,6 +471,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces { typeof(DoubleRestrictChildrenTagHelper), TagHelperDescriptorBuilder.Create(typeof(DoubleRestrictChildrenTagHelper).FullName, AssemblyName) + .TypeName(typeof(DoubleRestrictChildrenTagHelper).FullName) .TagMatchingRule(builder => builder.RequireTagName("double-restrict-children")) .AllowChildTag("p") .AllowChildTag("strong") @@ -472,6 +480,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces { typeof(MultiTargetRestrictChildrenTagHelper), TagHelperDescriptorBuilder.Create(typeof(MultiTargetRestrictChildrenTagHelper).FullName, AssemblyName) + .TypeName(typeof(MultiTargetRestrictChildrenTagHelper).FullName) .TagMatchingRule(builder => builder.RequireTagName("p")) .TagMatchingRule(builder => builder.RequireTagName("div")) .AllowChildTag("p") @@ -510,6 +519,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces { typeof(TagStructureTagHelper), TagHelperDescriptorBuilder.Create(typeof(TagStructureTagHelper).FullName, AssemblyName) + .TypeName(typeof(TagStructureTagHelper).FullName) .TagMatchingRule(builder => builder .RequireTagName("input") .RequireTagStructure(TagStructure.WithoutEndTag)) @@ -518,6 +528,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces { typeof(MultiSpecifiedTagStructureTagHelper), TagHelperDescriptorBuilder.Create(typeof(MultiSpecifiedTagStructureTagHelper).FullName, AssemblyName) + .TypeName(typeof(MultiSpecifiedTagStructureTagHelper).FullName) .TagMatchingRule(builder => builder .RequireTagName("p") .RequireTagStructure(TagStructure.NormalOrSelfClosing)) @@ -529,6 +540,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces { typeof(MultiWithUnspecifiedTagStructureTagHelper), TagHelperDescriptorBuilder.Create(typeof(MultiWithUnspecifiedTagStructureTagHelper).FullName, AssemblyName) + .TypeName(typeof(MultiWithUnspecifiedTagStructureTagHelper).FullName) .TagMatchingRule(builder => builder .RequireTagName("p")) .TagMatchingRule(builder => builder @@ -747,7 +759,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces TagHelperMatchingConventions.ElementCatchAllName, typeof(AttributeTargetingTagHelper).FullName, AssemblyName, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder.RequireAttribute(attribute => attribute.Name("class")), }) @@ -758,7 +770,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces TagHelperMatchingConventions.ElementCatchAllName, typeof(MultiAttributeTargetingTagHelper).FullName, AssemblyName, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => { @@ -774,7 +786,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces TagHelperMatchingConventions.ElementCatchAllName, typeof(MultiAttributeAttributeTargetingTagHelper).FullName, AssemblyName, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder.RequireAttribute(attribute => attribute.Name("custom")), builder => @@ -791,7 +803,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces TagHelperMatchingConventions.ElementCatchAllName, typeof(InheritedAttributeTargetingTagHelper).FullName, AssemblyName, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder.RequireAttribute(attribute => attribute.Name("style")), }) @@ -802,7 +814,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces "input", typeof(RequiredAttributeTagHelper).FullName, AssemblyName, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder.RequireAttribute(attribute => attribute.Name("class")), }) @@ -813,7 +825,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces "div", typeof(InheritedRequiredAttributeTagHelper).FullName, AssemblyName, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder.RequireAttribute(attribute => attribute.Name("class")), }) @@ -824,7 +836,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces "div", typeof(MultiAttributeRequiredAttributeTagHelper).FullName, AssemblyName, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder .RequireTagName("div") @@ -840,7 +852,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces "input", typeof(MultiAttributeSameTagRequiredAttributeTagHelper).FullName, AssemblyName, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder.RequireAttribute(attribute => attribute.Name("style")), builder => builder.RequireAttribute(attribute => attribute.Name("class")), @@ -852,7 +864,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces "input", typeof(MultiRequiredAttributeTagHelper).FullName, AssemblyName, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder .RequireAttribute(attribute => attribute.Name("class")) @@ -865,7 +877,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces "div", typeof(MultiTagMultiRequiredAttributeTagHelper).FullName, AssemblyName, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder .RequireTagName("div") @@ -883,7 +895,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces TagHelperMatchingConventions.ElementCatchAllName, typeof(AttributeWildcardTargetingTagHelper).FullName, AssemblyName, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder .RequireAttribute(attribute => attribute @@ -897,7 +909,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces TagHelperMatchingConventions.ElementCatchAllName, typeof(MultiAttributeWildcardTargetingTagHelper).FullName, AssemblyName, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder .RequireAttribute(attribute => attribute @@ -1038,15 +1050,15 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces } [Fact] - public void CreateDescriptor_AllowsOverridenAttributeNameOnUnimplementedVirtual() + public void CreateDescriptor_AllowsOverriddenAttributeNameOnUnimplementedVirtual() { // Arrange var validProperty1 = typeof(InheritedNotOverriddenAttributeTagHelper).GetProperty( nameof(InheritedNotOverriddenAttributeTagHelper.ValidAttribute1)); var validProperty2 = typeof(InheritedNotOverriddenAttributeTagHelper).GetProperty( nameof(InheritedNotOverriddenAttributeTagHelper.ValidAttribute2)); - var expectedDescriptor = - CreateTagHelperDescriptor( + + var expectedDescriptor = CreateTagHelperDescriptor( "inherited-not-overridden-attribute", typeof(InheritedNotOverriddenAttributeTagHelper).FullName, AssemblyName, @@ -1217,7 +1229,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces .PropertyName(nameof(MultiTagTagHelper.ValidAttribute)) .TypeName(typeof(string).FullName), }, - new Action[] + new Action[] { builder => builder.RequireTagName("p"), builder => builder.RequireTagName("div"), @@ -1262,16 +1274,16 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces public void CreateDescriptor_IgnoresDuplicateTagNamesFromAttribute() { // Arrange - var expectedDescriptor = - CreateTagHelperDescriptor( - string.Empty, - typeof(DuplicateTagNameTagHelper).FullName, - AssemblyName, - ruleBuilders: new Action[] - { - builder => builder.RequireTagName("p"), - builder => builder.RequireTagName("div"), - }); + var expectedDescriptor = CreateTagHelperDescriptor( + string.Empty, + typeof(DuplicateTagNameTagHelper).FullName, + AssemblyName, + ruleBuilders: new Action[] + { + builder => builder.RequireTagName("p"), + builder => builder.RequireTagName("div"), + }); + var factory = new DefaultTagHelperDescriptorFactory(Compilation, designTime: false); var typeSymbol = Compilation.GetTypeByMetadataName(typeof(DuplicateTagNameTagHelper).FullName); @@ -1376,6 +1388,9 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces { get { + var invalidBoundAttributeBuilder = new DefaultTagHelperDescriptorBuilder(TagHelperConventions.DefaultKind, nameof(InvalidBoundAttribute), "Test"); + invalidBoundAttributeBuilder.TypeName(typeof(InvalidBoundAttribute).FullName); + // type, expectedAttributeDescriptors return new TheoryData> { @@ -1383,80 +1398,72 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces typeof(InvalidBoundAttribute), new[] { - BoundAttributeDescriptorBuilder.Create(typeof(InvalidBoundAttribute).FullName) + CreateAttributeFor(typeof(InvalidBoundAttribute), attribute => + { + attribute .Name("data-something") .PropertyName(nameof(InvalidBoundAttribute.DataSomething)) - .TypeName(typeof(string).FullName) - .AddDiagnostic( - AspNetCore.Razor.Language.RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributeNameStartsWith( - typeof(InvalidBoundAttribute).FullName, - nameof(InvalidBoundAttribute.DataSomething), - "data-something")) - .Build() + .TypeName(typeof(string).FullName); + }), } }, { typeof(InvalidBoundAttributeWithValid), new[] { - BoundAttributeDescriptorBuilder.Create(typeof(InvalidBoundAttributeWithValid).FullName) + CreateAttributeFor(typeof(InvalidBoundAttributeWithValid), attribute => + { + attribute .Name("data-something") .PropertyName(nameof(InvalidBoundAttributeWithValid.DataSomething)) - .TypeName(typeof(string).FullName) - .AddDiagnostic( - AspNetCore.Razor.Language.RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributeNameStartsWith( - typeof(InvalidBoundAttributeWithValid).FullName, - nameof(InvalidBoundAttributeWithValid.DataSomething), - "data-something")) - .Build(), - BoundAttributeDescriptorBuilder.Create(typeof(InvalidBoundAttributeWithValid).FullName) + .TypeName(typeof(string).FullName); ; + }), + CreateAttributeFor(typeof(InvalidBoundAttributeWithValid), attribute => + { + attribute .Name("int-attribute") .PropertyName(nameof(InvalidBoundAttributeWithValid.IntAttribute)) - .TypeName(typeof(int).FullName) - .Build(), + .TypeName(typeof(int).FullName); + }), } }, { typeof(OverriddenInvalidBoundAttributeWithValid), new[] { - BoundAttributeDescriptorBuilder.Create(typeof(OverriddenInvalidBoundAttributeWithValid).FullName) + CreateAttributeFor(typeof(OverriddenInvalidBoundAttributeWithValid), attribute => + { + attribute .Name("valid-something") .PropertyName(nameof(OverriddenInvalidBoundAttributeWithValid.DataSomething)) - .TypeName(typeof(string).FullName) - .Build() + .TypeName(typeof(string).FullName); + }), } }, { typeof(OverriddenValidBoundAttributeWithInvalid), new[] { - BoundAttributeDescriptorBuilder.Create(typeof(OverriddenValidBoundAttributeWithInvalid).FullName) + CreateAttributeFor(typeof(OverriddenValidBoundAttributeWithInvalid), attribute => + { + attribute .Name("data-something") .PropertyName(nameof(OverriddenValidBoundAttributeWithInvalid.ValidSomething)) - .TypeName(typeof(string).FullName) - .AddDiagnostic( - AspNetCore.Razor.Language.RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributeNameStartsWith( - typeof(OverriddenValidBoundAttributeWithInvalid).FullName, - nameof(OverriddenValidBoundAttributeWithInvalid.ValidSomething), - "data-something")) - .Build() + .TypeName(typeof(string).FullName); + }), } }, { typeof(OverriddenValidBoundAttributeWithInvalidUpperCase), new[] { - BoundAttributeDescriptorBuilder.Create(typeof(OverriddenValidBoundAttributeWithInvalidUpperCase).FullName) + CreateAttributeFor(typeof(OverriddenValidBoundAttributeWithInvalidUpperCase), attribute => + { + attribute .Name("DATA-SOMETHING") .PropertyName(nameof(OverriddenValidBoundAttributeWithInvalidUpperCase.ValidSomething)) - .TypeName(typeof(string).FullName) - .AddDiagnostic( - AspNetCore.Razor.Language.RazorDiagnosticFactory.CreateTagHelper_InvalidBoundAttributeNameStartsWith( - typeof(OverriddenValidBoundAttributeWithInvalidUpperCase).FullName, - nameof(OverriddenValidBoundAttributeWithInvalidUpperCase.ValidSomething), - "DATA-SOMETHING")) - .Build() + .TypeName(typeof(string).FullName); + }), } }, }; @@ -1481,6 +1488,13 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces expectedAttributeDescriptors, descriptor.BoundAttributes, BoundAttributeDescriptorComparer.Default); + + var id = AspNetCore.Razor.Language.RazorDiagnosticFactory.TagHelper_InvalidBoundAttributeNameStartsWith.Id; + foreach (var attribute in descriptor.BoundAttributes.Where(a => a.Name.StartsWith("data-", StringComparison.OrdinalIgnoreCase))) + { + var diagnostic = Assert.Single(attribute.Diagnostics); + Assert.Equal(id, diagnostic.Id); + } } public static TheoryData ValidAttributeNameData @@ -1568,13 +1582,13 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces get { Func onNameError = (invalidText, invalidCharacter) => - "Invalid tag helper bound property 'DynamicTestTagHelper.InvalidProperty'. Tag helpers " + + "Invalid tag helper bound property 'string DynamicTestTagHelper.InvalidProperty' on tag helper 'DynamicTestTagHelper'. Tag helpers " + $"cannot bind to HTML attributes with name '{invalidText}' because the name contains a '{invalidCharacter}' character."; var whitespaceErrorString = - "Invalid tag helper bound property 'DynamicTestTagHelper.InvalidProperty'. Tag helpers cannot " + + "Invalid tag helper bound property 'string DynamicTestTagHelper.InvalidProperty' on tag helper 'DynamicTestTagHelper'. Tag helpers cannot " + "bind to HTML attributes with a null or empty name."; Func onDataError = invalidText => - "Invalid tag helper bound property 'DynamicTestTagHelper.InvalidProperty'. Tag helpers cannot bind "+ + "Invalid tag helper bound property 'string DynamicTestTagHelper.InvalidProperty' on tag helper 'DynamicTestTagHelper'. Tag helpers cannot bind " + $"to HTML attributes with name '{invalidText}' because the name starts with 'data-'."; return GetInvalidNameOrPrefixData(onNameError, whitespaceErrorString, onDataError); @@ -1612,12 +1626,15 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces get { Func onPrefixError = (invalidText, invalidCharacter) => - "Invalid tag helper bound property 'DynamicTestTagHelper.InvalidProperty'. Tag helpers "+ + "Invalid tag helper bound property 'System.Collections.Generic.IDictionary DynamicTestTagHelper.InvalidProperty' " + + "on tag helper 'DynamicTestTagHelper'. Tag helpers " + $"cannot bind to HTML attributes with prefix '{invalidText}' because the prefix contains a '{invalidCharacter}' character."; var whitespaceErrorString = - "Invalid tag helper bound property 'DynamicTestTagHelper.InvalidProperty'. Tag helpers cannot bind to HTML attributes with a null or empty name."; + "Invalid tag helper bound property 'System.Collections.Generic.IDictionary DynamicTestTagHelper.InvalidProperty' " + + "on tag helper 'DynamicTestTagHelper'. Tag helpers cannot bind to HTML attributes with a null or empty name."; Func onDataError = invalidText => - "Invalid tag helper bound property 'DynamicTestTagHelper.InvalidProperty'. Tag helpers cannot bind to HTML attributes "+ + "Invalid tag helper bound property 'System.Collections.Generic.IDictionary DynamicTestTagHelper.InvalidProperty' " + + "on tag helper 'DynamicTestTagHelper'. Tag helpers cannot bind to HTML attributes " + $"with prefix '{invalidText}' because the prefix starts with 'data-'."; return GetInvalidNameOrPrefixData(onPrefixError, whitespaceErrorString, onDataError); @@ -1634,7 +1651,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces public class DynamicTestTagHelper : {typeof(AspNetCore.Razor.TagHelpers.TagHelper).FullName} {{ [{typeof(AspNetCore.Razor.TagHelpers.HtmlAttributeNameAttribute).FullName}({nameof(AspNetCore.Razor.TagHelpers.HtmlAttributeNameAttribute.DictionaryAttributePrefix)} = ""{prefix}"")] - public System.Collections.Generic.IDictionary InvalidProperty {{ get; set; }} + public System.Collections.Generic.IDictionary InvalidProperty {{ get; set; }} }}"; var syntaxTree = CSharpSyntaxTree.ParseText(text); var compilation = TestCompilation.Create(_assembly, syntaxTree); @@ -1654,13 +1671,13 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces get { var nullOrWhiteSpaceError = - AspNetCore.Razor.Language.Resources.FormatInvalidRestrictedChildNullOrWhitespace("DynamicTestTagHelper"); + AspNetCore.Razor.Language.Resources.FormatTagHelper_InvalidRestrictedChildNullOrWhitespace("DynamicTestTagHelper"); return GetInvalidNameOrPrefixData( onNameError: (invalidInput, invalidCharacter) => - AspNetCore.Razor.Language.Resources.FormatInvalidRestrictedChild( - invalidInput, + AspNetCore.Razor.Language.Resources.FormatTagHelper_InvalidRestrictedChild( "DynamicTestTagHelper", + invalidInput, invalidCharacter), whitespaceErrorString: nullOrWhiteSpaceError, onDataError: null); @@ -1696,11 +1713,11 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces get { var nullOrWhiteSpaceError = - AspNetCore.Razor.Language.Resources.InvalidTargetedParentTagNameNullOrWhitespace; + AspNetCore.Razor.Language.Resources.TagHelper_InvalidTargetedParentTagNameNullOrWhitespace; return GetInvalidNameOrPrefixData( onNameError: (invalidInput, invalidCharacter) => - AspNetCore.Razor.Language.Resources.FormatInvalidTargetedParentTagName( + AspNetCore.Razor.Language.Resources.FormatTagHelper_InvalidTargetedParentTagName( invalidInput, invalidCharacter), whitespaceErrorString: nullOrWhiteSpaceError, @@ -1763,12 +1780,14 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces typeof(DefaultValidHtmlAttributePrefix), new[] { - BoundAttributeDescriptorBuilder.Create(typeof(DefaultValidHtmlAttributePrefix).FullName) + CreateAttributeFor(typeof(DefaultValidHtmlAttributePrefix), attribute => + { + attribute .Name("dictionary-property") .PropertyName(nameof(DefaultValidHtmlAttributePrefix.DictionaryProperty)) .TypeName($"{dictionaryNamespace}") - .AsDictionary("dictionary-property-", typeof(string).FullName) - .Build() + .AsDictionary("dictionary-property-", typeof(string).FullName); + }), }, Enumerable.Empty() }, @@ -1776,12 +1795,14 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces typeof(SingleValidHtmlAttributePrefix), new[] { - BoundAttributeDescriptorBuilder.Create(typeof(SingleValidHtmlAttributePrefix).FullName) + CreateAttributeFor(typeof(SingleValidHtmlAttributePrefix), attribute => + { + attribute .Name("valid-name") .PropertyName(nameof(SingleValidHtmlAttributePrefix.DictionaryProperty)) .TypeName($"{dictionaryNamespace}") - .AsDictionary("valid-name-", typeof(string).FullName) - .Build() + .AsDictionary("valid-name-", typeof(string).FullName); + }), }, Enumerable.Empty() }, @@ -1789,51 +1810,67 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces typeof(MultipleValidHtmlAttributePrefix), new[] { - BoundAttributeDescriptorBuilder.Create(typeof(MultipleValidHtmlAttributePrefix).FullName) + CreateAttributeFor(typeof(MultipleValidHtmlAttributePrefix), attribute => + { + attribute .Name("valid-name1") .PropertyName(nameof(MultipleValidHtmlAttributePrefix.DictionaryProperty)) .TypeName($"{typeof(Dictionary<,>).Namespace}.Dictionary") - .AsDictionary("valid-prefix1-", typeof(object).FullName) - .Build(), - BoundAttributeDescriptorBuilder.Create(typeof(MultipleValidHtmlAttributePrefix).FullName) + .AsDictionary("valid-prefix1-", typeof(object).FullName); + }), + CreateAttributeFor(typeof(MultipleValidHtmlAttributePrefix), attribute => + { + attribute .Name("valid-name2") .PropertyName(nameof(MultipleValidHtmlAttributePrefix.DictionarySubclassProperty)) .TypeName(typeof(DictionarySubclass).FullName) - .AsDictionary("valid-prefix2-", typeof(string).FullName) - .Build(), - BoundAttributeDescriptorBuilder.Create(typeof(MultipleValidHtmlAttributePrefix).FullName) + .AsDictionary("valid-prefix2-", typeof(string).FullName); + }), + CreateAttributeFor(typeof(MultipleValidHtmlAttributePrefix), attribute => + { + attribute .Name("valid-name3") .PropertyName(nameof(MultipleValidHtmlAttributePrefix.DictionaryWithoutParameterlessConstructorProperty)) .TypeName(typeof(DictionaryWithoutParameterlessConstructor).FullName) - .AsDictionary("valid-prefix3-", typeof(string).FullName) - .Build(), - BoundAttributeDescriptorBuilder.Create(typeof(MultipleValidHtmlAttributePrefix).FullName) + .AsDictionary("valid-prefix3-", typeof(string).FullName); + }), + CreateAttributeFor(typeof(MultipleValidHtmlAttributePrefix), attribute => + { + attribute .Name("valid-name4") .PropertyName(nameof(MultipleValidHtmlAttributePrefix.GenericDictionarySubclassProperty)) .TypeName(typeof(GenericDictionarySubclass).Namespace + ".GenericDictionarySubclass") - .AsDictionary("valid-prefix4-", typeof(object).FullName) - .Build(), - BoundAttributeDescriptorBuilder.Create(typeof(MultipleValidHtmlAttributePrefix).FullName) + .AsDictionary("valid-prefix4-", typeof(object).FullName); + }), + CreateAttributeFor(typeof(MultipleValidHtmlAttributePrefix), attribute => + { + attribute .Name("valid-name5") .PropertyName(nameof(MultipleValidHtmlAttributePrefix.SortedDictionaryProperty)) .TypeName(typeof(SortedDictionary).Namespace + ".SortedDictionary") - .AsDictionary("valid-prefix5-", typeof(int).FullName) - .Build(), - BoundAttributeDescriptorBuilder.Create(typeof(MultipleValidHtmlAttributePrefix).FullName) + .AsDictionary("valid-prefix5-", typeof(int).FullName); + }), + CreateAttributeFor(typeof(MultipleValidHtmlAttributePrefix), attribute => + { + attribute .Name("valid-name6") .PropertyName(nameof(MultipleValidHtmlAttributePrefix.StringProperty)) - .TypeName(typeof(string).FullName) - .Build(), - BoundAttributeDescriptorBuilder.Create(typeof(MultipleValidHtmlAttributePrefix).FullName) + .TypeName(typeof(string).FullName); + }), + CreateAttributeFor(typeof(MultipleValidHtmlAttributePrefix), attribute => + { + attribute .PropertyName(nameof(MultipleValidHtmlAttributePrefix.GetOnlyDictionaryProperty)) .TypeName($"{dictionaryNamespace}") - .AsDictionary("get-only-dictionary-property-", typeof(int).FullName) - .Build(), - BoundAttributeDescriptorBuilder.Create(typeof(MultipleValidHtmlAttributePrefix).FullName) + .AsDictionary("get-only-dictionary-property-", typeof(int).FullName); + }), + CreateAttributeFor(typeof(MultipleValidHtmlAttributePrefix), attribute => + { + attribute .PropertyName(nameof(MultipleValidHtmlAttributePrefix.GetOnlyDictionaryPropertyWithAttributePrefix)) .TypeName($"{dictionaryNamespace}") - .AsDictionary("valid-prefix6", typeof(string).FullName) - .Build() + .AsDictionary("valid-prefix6", typeof(string).FullName); + }), }, Enumerable.Empty() }, @@ -1841,14 +1878,16 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces typeof(SingleInvalidHtmlAttributePrefix), new[] { - BoundAttributeDescriptorBuilder.Create(typeof(SingleInvalidHtmlAttributePrefix).FullName) + CreateAttributeFor(typeof(SingleInvalidHtmlAttributePrefix), attribute => + { + attribute .Name("valid-name") .PropertyName(nameof(SingleInvalidHtmlAttributePrefix.StringProperty)) .TypeName(typeof(string).FullName) .AddDiagnostic(RazorDiagnosticFactory.CreateTagHelper_InvalidAttributePrefixNotNull( typeof(SingleInvalidHtmlAttributePrefix).FullName, - nameof(SingleInvalidHtmlAttributePrefix.StringProperty))) - .Build(), + nameof(SingleInvalidHtmlAttributePrefix.StringProperty))); + }), }, new[] { @@ -1861,12 +1900,16 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces typeof(MultipleInvalidHtmlAttributePrefix), new[] { - BoundAttributeDescriptorBuilder.Create(typeof(MultipleInvalidHtmlAttributePrefix).FullName) + CreateAttributeFor(typeof(MultipleInvalidHtmlAttributePrefix), attribute => + { + attribute .Name("valid-name1") .PropertyName(nameof(MultipleInvalidHtmlAttributePrefix.LongProperty)) - .TypeName(typeof(long).FullName) - .Build(), - BoundAttributeDescriptorBuilder.Create(typeof(MultipleInvalidHtmlAttributePrefix).FullName) + .TypeName(typeof(long).FullName); + }), + CreateAttributeFor(typeof(MultipleInvalidHtmlAttributePrefix), attribute => + { + attribute .Name("valid-name2") .PropertyName(nameof(MultipleInvalidHtmlAttributePrefix.DictionaryOfIntProperty)) .TypeName($"{typeof(Dictionary<,>).Namespace}.Dictionary") @@ -1874,27 +1917,33 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces .AddDiagnostic( RazorDiagnosticFactory.CreateTagHelper_InvalidAttributePrefixNotNull( typeof(MultipleInvalidHtmlAttributePrefix).FullName, - nameof(MultipleInvalidHtmlAttributePrefix.DictionaryOfIntProperty))) - .Build(), - BoundAttributeDescriptorBuilder.Create(typeof(MultipleInvalidHtmlAttributePrefix).FullName) + nameof(MultipleInvalidHtmlAttributePrefix.DictionaryOfIntProperty))); + }), + CreateAttributeFor(typeof(MultipleInvalidHtmlAttributePrefix), attribute => + { + attribute .Name("valid-name3") .PropertyName(nameof(MultipleInvalidHtmlAttributePrefix.ReadOnlyDictionaryProperty)) .TypeName($"{typeof(IReadOnlyDictionary<,>).Namespace}.IReadOnlyDictionary") .AddDiagnostic( RazorDiagnosticFactory.CreateTagHelper_InvalidAttributePrefixNotNull( typeof(MultipleInvalidHtmlAttributePrefix).FullName, - nameof(MultipleInvalidHtmlAttributePrefix.ReadOnlyDictionaryProperty))) - .Build(), - BoundAttributeDescriptorBuilder.Create(typeof(MultipleInvalidHtmlAttributePrefix).FullName) + nameof(MultipleInvalidHtmlAttributePrefix.ReadOnlyDictionaryProperty))); + }), + CreateAttributeFor(typeof(MultipleInvalidHtmlAttributePrefix), attribute => + { + attribute .Name("valid-name4") .PropertyName(nameof(MultipleInvalidHtmlAttributePrefix.IntProperty)) .TypeName(typeof(int).FullName) .AddDiagnostic( RazorDiagnosticFactory.CreateTagHelper_InvalidAttributePrefixNotNull( typeof(MultipleInvalidHtmlAttributePrefix).FullName, - nameof(MultipleInvalidHtmlAttributePrefix.IntProperty))) - .Build(), - BoundAttributeDescriptorBuilder.Create(typeof(MultipleInvalidHtmlAttributePrefix).FullName) + nameof(MultipleInvalidHtmlAttributePrefix.IntProperty))); + }), + CreateAttributeFor(typeof(MultipleInvalidHtmlAttributePrefix), attribute => + { + attribute .Name("valid-name5") .PropertyName(nameof(MultipleInvalidHtmlAttributePrefix.DictionaryOfIntSubclassProperty)) .TypeName(typeof(DictionaryOfIntSubclass).FullName) @@ -1902,26 +1951,30 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces .AddDiagnostic( RazorDiagnosticFactory.CreateTagHelper_InvalidAttributePrefixNotNull( typeof(MultipleInvalidHtmlAttributePrefix).FullName, - nameof(MultipleInvalidHtmlAttributePrefix.DictionaryOfIntSubclassProperty))) - .Build(), - BoundAttributeDescriptorBuilder.Create(typeof(MultipleInvalidHtmlAttributePrefix).FullName) + nameof(MultipleInvalidHtmlAttributePrefix.DictionaryOfIntSubclassProperty))); + }), + CreateAttributeFor(typeof(MultipleInvalidHtmlAttributePrefix), attribute => + { + attribute .PropertyName(nameof(MultipleInvalidHtmlAttributePrefix.GetOnlyDictionaryAttributePrefix)) .TypeName($"{dictionaryNamespace}") .AsDictionary("valid-prefix6", typeof(string).FullName) .AddDiagnostic( RazorDiagnosticFactory.CreateTagHelper_InvalidAttributePrefixNotNull( typeof(MultipleInvalidHtmlAttributePrefix).FullName, - nameof(MultipleInvalidHtmlAttributePrefix.GetOnlyDictionaryAttributePrefix))) - .Build(), - BoundAttributeDescriptorBuilder.Create(typeof(MultipleInvalidHtmlAttributePrefix).FullName) + nameof(MultipleInvalidHtmlAttributePrefix.GetOnlyDictionaryAttributePrefix))); + }), + CreateAttributeFor(typeof(MultipleInvalidHtmlAttributePrefix), attribute => + { + attribute .PropertyName(nameof(MultipleInvalidHtmlAttributePrefix.GetOnlyDictionaryPropertyWithAttributeName)) .TypeName($"{dictionaryNamespace}") .AsDictionary("invalid-name7-", typeof(object).FullName) .AddDiagnostic( RazorDiagnosticFactory.CreateTagHelper_InvalidAttributePrefixNull( typeof(MultipleInvalidHtmlAttributePrefix).FullName, - nameof(MultipleInvalidHtmlAttributePrefix.GetOnlyDictionaryPropertyWithAttributeName))) - .Build(), + nameof(MultipleInvalidHtmlAttributePrefix.GetOnlyDictionaryPropertyWithAttributeName))); + }), }, new[] { @@ -1981,6 +2034,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces { typeof(MultipleDescriptorTagHelperWithOutputElementHint), TagHelperDescriptorBuilder.Create(typeof(MultipleDescriptorTagHelperWithOutputElementHint).FullName, AssemblyName) + .TypeName(typeof(MultipleDescriptorTagHelperWithOutputElementHint).FullName) .TagMatchingRule(builder => builder.RequireTagName("a")) .TagMatchingRule(builder => builder.RequireTagName("p")) .TagOutputHint("div") @@ -1989,12 +2043,14 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces { typeof(InheritedOutputElementHintTagHelper), TagHelperDescriptorBuilder.Create(typeof(InheritedOutputElementHintTagHelper).FullName, AssemblyName) + .TypeName(typeof(InheritedOutputElementHintTagHelper).FullName) .TagMatchingRule(builder => builder.RequireTagName("inherited-output-element-hint")) .Build() }, { typeof(OutputElementHintTagHelper), TagHelperDescriptorBuilder.Create(typeof(OutputElementHintTagHelper).FullName, AssemblyName) + .TypeName(typeof(OutputElementHintTagHelper).FullName) .TagMatchingRule(builder => builder.RequireTagName("output-element-hint")) .TagOutputHint("hinted-value") .Build() @@ -2002,6 +2058,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces { typeof(OverriddenOutputElementHintTagHelper), TagHelperDescriptorBuilder.Create(typeof(OverriddenOutputElementHintTagHelper).FullName, AssemblyName) + .TypeName(typeof(OverriddenOutputElementHintTagHelper).FullName) .TagMatchingRule(builder => builder.RequireTagName("overridden-output-element-hint")) .TagOutputHint("overridden") .Build() @@ -2264,9 +2321,10 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces string typeName, string assemblyName, IEnumerable> attributes = null, - IEnumerable> ruleBuilders = null) + IEnumerable> ruleBuilders = null) { var builder = TagHelperDescriptorBuilder.Create(typeName, assemblyName); + builder.TypeName(typeName); if (attributes != null) { @@ -2296,6 +2354,16 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces return descriptor; } + + private static BoundAttributeDescriptor CreateAttributeFor(Type tagHelperType, Action configure) + { + var tagHelperBuilder = new DefaultTagHelperDescriptorBuilder(TagHelperConventions.DefaultKind, tagHelperType.Name, "Test"); + tagHelperBuilder.TypeName(tagHelperType.FullName); + + var attributeBuilder = new DefaultBoundAttributeDescriptorBuilder(tagHelperBuilder, TagHelperConventions.DefaultKind); + configure(attributeBuilder); + return attributeBuilder.Build(); + } } [AspNetCore.Razor.TagHelpers.OutputElementHint("hinted-value")] diff --git a/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DefaultTagHelperFactsServiceTest.cs b/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DefaultTagHelperFactsServiceTest.cs index acd5a54925..6f9afac1df 100644 --- a/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DefaultTagHelperFactsServiceTest.cs +++ b/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DefaultTagHelperFactsServiceTest.cs @@ -79,7 +79,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor var descriptor = Assert.Single(binding.Descriptors); Assert.Equal(documentDescriptors[0], descriptor, TagHelperDescriptorComparer.CaseSensitive); var boundRule = Assert.Single(binding.GetBoundRules(descriptor)); - Assert.Equal(documentDescriptors[0].TagMatchingRules.First(), boundRule, TagMatchingRuleComparer.CaseSensitive); + Assert.Equal(documentDescriptors[0].TagMatchingRules.First(), boundRule, TagMatchingRuleDescriptorComparer.CaseSensitive); } [Fact] diff --git a/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TagHelperDescriptorSerializationTest.cs b/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TagHelperDescriptorSerializationTest.cs index ffd16b23ac..169f69fd58 100644 --- a/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TagHelperDescriptorSerializationTest.cs +++ b/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TagHelperDescriptorSerializationTest.cs @@ -27,7 +27,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor .PropertyName("TestAttribute") .TypeName("string"), }, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder .RequireAttribute(attribute => attribute @@ -70,7 +70,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor .PropertyName("TestAttribute") .TypeName("string"), }, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder .RequireAttribute(attribute => attribute @@ -122,7 +122,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor .TypeName("SomeDictionary") .AsDictionary("dict-prefix-", "string"), }, - ruleBuilders: new Action[] + ruleBuilders: new Action[] { builder => builder .RequireAttribute(attribute => attribute @@ -150,10 +150,11 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor string typeName, string assemblyName, IEnumerable> attributes = null, - IEnumerable> ruleBuilders = null, + IEnumerable> ruleBuilders = null, Action configureAction = null) { var builder = TagHelperDescriptorBuilder.Create(typeName, assemblyName); + builder.TypeName(typeName); if (attributes != null) {