From d9173118831f905544f8d3098d0c0fe0f5d1964b Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Tue, 23 May 2017 15:41:03 -0700 Subject: [PATCH] Make ViewComponentTagHelper's bound attribute display names nicer. - Went from `typeName __Generated__SomeViewComponentTagHelper.PropertyName` to `typeName SomeViewComponentTagHelper.PropertyName`. - Updated `TagHelperBoundDescriptorBuilder` to allow setting of `DisplayName`. - Added `TagHelperBoundAttributeDescriptorBuilderTest` class to verify new `DisplayName` additions. - Updated `ViewComponentTagHelperDescriptorFactoryTest` expectations. #1251 --- .../BoundAttributeDescriptorBuilder.cs | 24 ++++++++++-- ...ViewComponentTagHelperDescriptorFactory.cs | 33 ++++++++++++++-- .../BoundAttributeDescriptorBuilderTest.cs | 39 +++++++++++++++++++ ...ComponentTagHelperDescriptorFactoryTest.cs | 21 ++++++---- ...omponentTagHelperDescriptorProviderTest.cs | 9 ++--- 5 files changed, 108 insertions(+), 18 deletions(-) create mode 100644 test/Microsoft.AspNetCore.Razor.Language.Test/BoundAttributeDescriptorBuilderTest.cs diff --git a/src/Microsoft.AspNetCore.Razor.Language/BoundAttributeDescriptorBuilder.cs b/src/Microsoft.AspNetCore.Razor.Language/BoundAttributeDescriptorBuilder.cs index 07f6c52814..29d1daf87d 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/BoundAttributeDescriptorBuilder.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/BoundAttributeDescriptorBuilder.cs @@ -31,6 +31,7 @@ namespace Microsoft.AspNetCore.Razor.Language [typeof(decimal).FullName] = "decimal", }; + private string _displayName; private bool _isEnum; private bool _hasIndexer; private string _indexerValueTypeName; @@ -113,6 +114,18 @@ namespace Microsoft.AspNetCore.Razor.Language 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(); @@ -122,12 +135,17 @@ namespace Microsoft.AspNetCore.Razor.Language diagnostics.UnionWith(_diagnostics); } - if (!PrimitiveDisplayTypeNameLookups.TryGetValue(_typeName, out var simpleName)) + var displayName = _displayName; + if (displayName == null) { - simpleName = _typeName; + if (!PrimitiveDisplayTypeNameLookups.TryGetValue(_typeName, out var simpleName)) + { + simpleName = _typeName; + } + + displayName = $"{simpleName} {_containingTypeName}.{_propertyName}"; } - var displayName = $"{simpleName} {_containingTypeName}.{_propertyName}"; var descriptor = new ITagHelperBoundAttributeDescriptor( _isEnum, _name, diff --git a/src/Microsoft.CodeAnalysis.Razor/ViewComponentTagHelperDescriptorFactory.cs b/src/Microsoft.CodeAnalysis.Razor/ViewComponentTagHelperDescriptorFactory.cs index 45c9374ae3..8c6392dfc9 100644 --- a/src/Microsoft.CodeAnalysis.Razor/ViewComponentTagHelperDescriptorFactory.cs +++ b/src/Microsoft.CodeAnalysis.Razor/ViewComponentTagHelperDescriptorFactory.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.AspNetCore.Razor.Language; @@ -20,6 +21,25 @@ namespace Microsoft.CodeAnalysis.Razor .WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted) .WithMiscellaneousOptions(SymbolDisplayFormat.FullyQualifiedFormat.MiscellaneousOptions & (~SymbolDisplayMiscellaneousOptions.UseSpecialTypes)); + 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 ViewComponentTagHelperDescriptorFactory(Compilation compilation) { _viewComponentAttributeSymbol = compilation.GetTypeByMetadataName(ViewComponentTypes.ViewComponentAttribute); @@ -47,7 +67,7 @@ namespace Microsoft.CodeAnalysis.Razor AddRequiredAttributes(methodParameters, ruleBuilder); }); - AddBoundAttributes(methodParameters, descriptorBuilder); + AddBoundAttributes(methodParameters, displayName, descriptorBuilder); } else { @@ -148,18 +168,25 @@ namespace Microsoft.CodeAnalysis.Razor } } - private void AddBoundAttributes(ImmutableArray methodParameters, TagHelperDescriptorBuilder builder) + private void AddBoundAttributes(ImmutableArray methodParameters, string containingDisplayName, TagHelperDescriptorBuilder builder) { foreach (var parameter in methodParameters) { var lowerKebabName = HtmlConventions.ToHtmlCase(parameter.Name); var typeName = parameter.Type.ToDisplayString(FullNameTypeDisplayFormat); + + if (!PrimitiveDisplayTypeNameLookups.TryGetValue(typeName, out var simpleName)) + { + simpleName = typeName; + } + builder.BindAttribute(attributeBuilder => { attributeBuilder .Name(lowerKebabName) .PropertyName(parameter.Name) - .TypeName(typeName); + .TypeName(typeName) + .DisplayName($"{simpleName} {containingDisplayName}.{parameter.Name}"); if (parameter.Type.TypeKind == TypeKind.Enum) { diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/BoundAttributeDescriptorBuilderTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/BoundAttributeDescriptorBuilderTest.cs new file mode 100644 index 0000000000..ff3a3d11bd --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/BoundAttributeDescriptorBuilderTest.cs @@ -0,0 +1,39 @@ +// 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 Xunit; + +namespace Microsoft.AspNetCore.Razor.Language +{ + public class BoundAttributeDescriptorBuilderTest + { + [Fact] + public void DisplayName_SetsDescriptorsDisplayName() + { + // Arrange + var expectedDisplayName = "ExpectedDisplayName"; + var builder = BoundAttributeDescriptorBuilder.Create("TestTagHelper"); + + // Act + var descriptor = builder.DisplayName(expectedDisplayName).Build(); + + // Assert + Assert.Equal(expectedDisplayName, descriptor.DisplayName); + } + + [Fact] + public void DisplayName_DefaultsToPropertyLookingDisplayName() + { + // Arrange + var builder = BoundAttributeDescriptorBuilder.Create("TestTagHelper") + .TypeName(typeof(int).FullName) + .PropertyName("SomeProperty"); + + // Act + var descriptor = builder.Build(); + + // Assert + Assert.Equal("int TestTagHelper.SomeProperty", descriptor.DisplayName); + } + } +} diff --git a/test/Microsoft.CodeAnalysis.Razor.Test/ViewComponentTagHelperDescriptorFactoryTest.cs b/test/Microsoft.CodeAnalysis.Razor.Test/ViewComponentTagHelperDescriptorFactoryTest.cs index a05a8c96fe..df25cd201d 100644 --- a/test/Microsoft.CodeAnalysis.Razor.Test/ViewComponentTagHelperDescriptorFactoryTest.cs +++ b/test/Microsoft.CodeAnalysis.Razor.Test/ViewComponentTagHelperDescriptorFactoryTest.cs @@ -31,12 +31,14 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces attribute .Name("foo") .PropertyName("foo") - .TypeName(typeof(string).FullName)) + .TypeName(typeof(string).FullName) + .DisplayName("string StringParameterViewComponentTagHelper.foo")) .BindAttribute(attribute => attribute .Name("bar") .PropertyName("bar") - .TypeName(typeof(string).FullName)) + .TypeName(typeof(string).FullName) + .DisplayName("string StringParameterViewComponentTagHelper.bar")) .AddMetadata(ViewComponentTypes.ViewComponentNameKey, "StringParameter") .Build(); @@ -69,17 +71,20 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces .Name("test-enum") .PropertyName("testEnum") .TypeName(typeof(VariousParameterViewComponent).FullName + "." + nameof(VariousParameterViewComponent.TestEnum)) - .AsEnum()) + .AsEnum() + .DisplayName(typeof(VariousParameterViewComponent).FullName + "." + nameof(VariousParameterViewComponent.TestEnum) + " VariousParameterViewComponentTagHelper.testEnum")) .BindAttribute(attribute => attribute .Name("test-string") .PropertyName("testString") - .TypeName(typeof(string).FullName)) + .TypeName(typeof(string).FullName) + .DisplayName("string VariousParameterViewComponentTagHelper.testString")) .BindAttribute(attribute => attribute .Name("baz") .PropertyName("baz") - .TypeName(typeof(int).FullName)) + .TypeName(typeof(int).FullName) + .DisplayName("int VariousParameterViewComponentTagHelper.baz")) .AddMetadata(ViewComponentTypes.ViewComponentNameKey, "VariousParameter") .Build(); @@ -109,13 +114,15 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces attribute .Name("foo") .PropertyName("Foo") - .TypeName("System.Collections.Generic.List")) + .TypeName("System.Collections.Generic.List") + .DisplayName("System.Collections.Generic.List GenericParameterViewComponentTagHelper.Foo")) .BindAttribute(attribute => attribute .Name("bar") .PropertyName("Bar") .TypeName("System.Collections.Generic.Dictionary") - .AsDictionary("bar-", typeof(int).FullName)) + .AsDictionary("bar-", typeof(int).FullName) + .DisplayName("System.Collections.Generic.Dictionary GenericParameterViewComponentTagHelper.Bar")) .AddMetadata(ViewComponentTypes.ViewComponentNameKey, "GenericParameter") .Build(); diff --git a/test/Microsoft.CodeAnalysis.Razor.Test/ViewComponentTagHelperDescriptorProviderTest.cs b/test/Microsoft.CodeAnalysis.Razor.Test/ViewComponentTagHelperDescriptorProviderTest.cs index dd9a801587..6a466c8c5e 100644 --- a/test/Microsoft.CodeAnalysis.Razor.Test/ViewComponentTagHelperDescriptorProviderTest.cs +++ b/test/Microsoft.CodeAnalysis.Razor.Test/ViewComponentTagHelperDescriptorProviderTest.cs @@ -1,10 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; -using System.Collections.Generic; using System.Linq; -using System.Reflection; using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.CSharp; using Xunit; @@ -49,12 +46,14 @@ namespace Microsoft.CodeAnalysis.Razor attribute .Name("foo") .PropertyName("foo") - .TypeName(typeof(string).FullName)) + .TypeName(typeof(string).FullName) + .DisplayName("string StringParameterViewComponentTagHelper.foo")) .BindAttribute(attribute => attribute .Name("bar") .PropertyName("bar") - .TypeName(typeof(string).FullName)) + .TypeName(typeof(string).FullName) + .DisplayName("string StringParameterViewComponentTagHelper.bar")) .AddMetadata(ViewComponentTypes.ViewComponentNameKey, "StringParameter") .Build();