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
This commit is contained in:
N. Taylor Mullen 2017-05-23 15:41:03 -07:00
parent cdddaefa81
commit d917311883
5 changed files with 108 additions and 18 deletions

View File

@ -31,6 +31,7 @@ namespace Microsoft.AspNetCore.Razor.Language
[typeof(decimal).FullName] = "decimal", [typeof(decimal).FullName] = "decimal",
}; };
private string _displayName;
private bool _isEnum; private bool _isEnum;
private bool _hasIndexer; private bool _hasIndexer;
private string _indexerValueTypeName; private string _indexerValueTypeName;
@ -113,6 +114,18 @@ namespace Microsoft.AspNetCore.Razor.Language
return this; return this;
} }
public BoundAttributeDescriptorBuilder DisplayName(string displayName)
{
if (displayName == null)
{
throw new ArgumentNullException(nameof(displayName));
}
_displayName = displayName;
return this;
}
public BoundAttributeDescriptor Build() public BoundAttributeDescriptor Build()
{ {
var validationDiagnostics = Validate(); var validationDiagnostics = Validate();
@ -122,12 +135,17 @@ namespace Microsoft.AspNetCore.Razor.Language
diagnostics.UnionWith(_diagnostics); 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( var descriptor = new ITagHelperBoundAttributeDescriptor(
_isEnum, _isEnum,
_name, _name,

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language;
@ -20,6 +21,25 @@ namespace Microsoft.CodeAnalysis.Razor
.WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted) .WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted)
.WithMiscellaneousOptions(SymbolDisplayFormat.FullyQualifiedFormat.MiscellaneousOptions & (~SymbolDisplayMiscellaneousOptions.UseSpecialTypes)); .WithMiscellaneousOptions(SymbolDisplayFormat.FullyQualifiedFormat.MiscellaneousOptions & (~SymbolDisplayMiscellaneousOptions.UseSpecialTypes));
private static readonly IReadOnlyDictionary<string, string> PrimitiveDisplayTypeNameLookups = new Dictionary<string, string>(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) public ViewComponentTagHelperDescriptorFactory(Compilation compilation)
{ {
_viewComponentAttributeSymbol = compilation.GetTypeByMetadataName(ViewComponentTypes.ViewComponentAttribute); _viewComponentAttributeSymbol = compilation.GetTypeByMetadataName(ViewComponentTypes.ViewComponentAttribute);
@ -47,7 +67,7 @@ namespace Microsoft.CodeAnalysis.Razor
AddRequiredAttributes(methodParameters, ruleBuilder); AddRequiredAttributes(methodParameters, ruleBuilder);
}); });
AddBoundAttributes(methodParameters, descriptorBuilder); AddBoundAttributes(methodParameters, displayName, descriptorBuilder);
} }
else else
{ {
@ -148,18 +168,25 @@ namespace Microsoft.CodeAnalysis.Razor
} }
} }
private void AddBoundAttributes(ImmutableArray<IParameterSymbol> methodParameters, TagHelperDescriptorBuilder builder) private void AddBoundAttributes(ImmutableArray<IParameterSymbol> methodParameters, string containingDisplayName, TagHelperDescriptorBuilder builder)
{ {
foreach (var parameter in methodParameters) foreach (var parameter in methodParameters)
{ {
var lowerKebabName = HtmlConventions.ToHtmlCase(parameter.Name); var lowerKebabName = HtmlConventions.ToHtmlCase(parameter.Name);
var typeName = parameter.Type.ToDisplayString(FullNameTypeDisplayFormat); var typeName = parameter.Type.ToDisplayString(FullNameTypeDisplayFormat);
if (!PrimitiveDisplayTypeNameLookups.TryGetValue(typeName, out var simpleName))
{
simpleName = typeName;
}
builder.BindAttribute(attributeBuilder => builder.BindAttribute(attributeBuilder =>
{ {
attributeBuilder attributeBuilder
.Name(lowerKebabName) .Name(lowerKebabName)
.PropertyName(parameter.Name) .PropertyName(parameter.Name)
.TypeName(typeName); .TypeName(typeName)
.DisplayName($"{simpleName} {containingDisplayName}.{parameter.Name}");
if (parameter.Type.TypeKind == TypeKind.Enum) if (parameter.Type.TypeKind == TypeKind.Enum)
{ {

View File

@ -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);
}
}
}

View File

@ -31,12 +31,14 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces
attribute attribute
.Name("foo") .Name("foo")
.PropertyName("foo") .PropertyName("foo")
.TypeName(typeof(string).FullName)) .TypeName(typeof(string).FullName)
.DisplayName("string StringParameterViewComponentTagHelper.foo"))
.BindAttribute(attribute => .BindAttribute(attribute =>
attribute attribute
.Name("bar") .Name("bar")
.PropertyName("bar") .PropertyName("bar")
.TypeName(typeof(string).FullName)) .TypeName(typeof(string).FullName)
.DisplayName("string StringParameterViewComponentTagHelper.bar"))
.AddMetadata(ViewComponentTypes.ViewComponentNameKey, "StringParameter") .AddMetadata(ViewComponentTypes.ViewComponentNameKey, "StringParameter")
.Build(); .Build();
@ -69,17 +71,20 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces
.Name("test-enum") .Name("test-enum")
.PropertyName("testEnum") .PropertyName("testEnum")
.TypeName(typeof(VariousParameterViewComponent).FullName + "." + nameof(VariousParameterViewComponent.TestEnum)) .TypeName(typeof(VariousParameterViewComponent).FullName + "." + nameof(VariousParameterViewComponent.TestEnum))
.AsEnum()) .AsEnum()
.DisplayName(typeof(VariousParameterViewComponent).FullName + "." + nameof(VariousParameterViewComponent.TestEnum) + " VariousParameterViewComponentTagHelper.testEnum"))
.BindAttribute(attribute => .BindAttribute(attribute =>
attribute attribute
.Name("test-string") .Name("test-string")
.PropertyName("testString") .PropertyName("testString")
.TypeName(typeof(string).FullName)) .TypeName(typeof(string).FullName)
.DisplayName("string VariousParameterViewComponentTagHelper.testString"))
.BindAttribute(attribute => .BindAttribute(attribute =>
attribute attribute
.Name("baz") .Name("baz")
.PropertyName("baz") .PropertyName("baz")
.TypeName(typeof(int).FullName)) .TypeName(typeof(int).FullName)
.DisplayName("int VariousParameterViewComponentTagHelper.baz"))
.AddMetadata(ViewComponentTypes.ViewComponentNameKey, "VariousParameter") .AddMetadata(ViewComponentTypes.ViewComponentNameKey, "VariousParameter")
.Build(); .Build();
@ -109,13 +114,15 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces
attribute attribute
.Name("foo") .Name("foo")
.PropertyName("Foo") .PropertyName("Foo")
.TypeName("System.Collections.Generic.List<System.String>")) .TypeName("System.Collections.Generic.List<System.String>")
.DisplayName("System.Collections.Generic.List<System.String> GenericParameterViewComponentTagHelper.Foo"))
.BindAttribute(attribute => .BindAttribute(attribute =>
attribute attribute
.Name("bar") .Name("bar")
.PropertyName("Bar") .PropertyName("Bar")
.TypeName("System.Collections.Generic.Dictionary<System.String, System.Int32>") .TypeName("System.Collections.Generic.Dictionary<System.String, System.Int32>")
.AsDictionary("bar-", typeof(int).FullName)) .AsDictionary("bar-", typeof(int).FullName)
.DisplayName("System.Collections.Generic.Dictionary<System.String, System.Int32> GenericParameterViewComponentTagHelper.Bar"))
.AddMetadata(ViewComponentTypes.ViewComponentNameKey, "GenericParameter") .AddMetadata(ViewComponentTypes.ViewComponentNameKey, "GenericParameter")
.Build(); .Build();

View File

@ -1,10 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp;
using Xunit; using Xunit;
@ -49,12 +46,14 @@ namespace Microsoft.CodeAnalysis.Razor
attribute attribute
.Name("foo") .Name("foo")
.PropertyName("foo") .PropertyName("foo")
.TypeName(typeof(string).FullName)) .TypeName(typeof(string).FullName)
.DisplayName("string StringParameterViewComponentTagHelper.foo"))
.BindAttribute(attribute => .BindAttribute(attribute =>
attribute attribute
.Name("bar") .Name("bar")
.PropertyName("bar") .PropertyName("bar")
.TypeName(typeof(string).FullName)) .TypeName(typeof(string).FullName)
.DisplayName("string StringParameterViewComponentTagHelper.bar"))
.AddMetadata(ViewComponentTypes.ViewComponentNameKey, "StringParameter") .AddMetadata(ViewComponentTypes.ViewComponentNameKey, "StringParameter")
.Build(); .Build();