Remove magic string keys from TH builders.

- Replaced the magic strings with extension methods that produce the same behavior as the string keys did.
- Added tests to validate new extension methods.

#1307
This commit is contained in:
N. Taylor Mullen 2017-05-16 10:59:33 -07:00
parent 315221c758
commit 5aababce6e
14 changed files with 215 additions and 22 deletions

View File

@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
GenerateVCTHClass(visitor.Class, tagHelper.Value);
var tagHelperTypeName = tagHelper.Value.Metadata[TagHelperDescriptorBuilder.TypeNameKey];
var tagHelperTypeName = tagHelper.Value.GetTypeName();
if (visitor.Fields.UsedTagHelperTypeNames.Remove(tagHelperTypeName))
{
visitor.Fields.UsedTagHelperTypeNames.Add(GetVCTHFullName(visitor.Namespace, visitor.Class, tagHelper.Value));
@ -155,7 +155,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
foreach (var attribute in descriptor.BoundAttributes)
{
writer.WriteAutoPropertyDeclaration(
"public", attribute.TypeName, attribute.Metadata[TagHelperBoundAttributeDescriptorBuilder.PropertyNameKey]);
"public", attribute.TypeName, attribute.GetPropertyName());
if (attribute.IndexerTypeName != null)
{
@ -203,7 +203,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
private string[] GetMethodParameters(TagHelperDescriptor descriptor)
{
var propertyNames = descriptor.BoundAttributes.Select(
attribute => attribute.Metadata[TagHelperBoundAttributeDescriptorBuilder.PropertyNameKey]);
attribute => attribute.GetPropertyName());
var joinedPropertyNames = string.Join(", ", propertyNames);
var parametersString = $"new {{ { joinedPropertyNames } }}";

View File

@ -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 static class BoundAttributeDescriptorExtensions
{
public static string GetPropertyName(this BoundAttributeDescriptor descriptor)
{
descriptor.Metadata.TryGetValue(TagHelperBoundAttributeDescriptorBuilder.PropertyNameKey, out var propertyName);
return propertyName;
}
public static bool IsDefaultKind(this BoundAttributeDescriptor descriptor)
=> string.Equals(descriptor.Kind, TagHelperBoundAttributeDescriptorBuilder.DescriptorKind, StringComparison.Ordinal);
}
}

View File

@ -196,7 +196,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration
string attributeName,
BoundAttributeDescriptor descriptor)
{
var propertyAccessor = $"{tagHelperVariableName}.{descriptor.Metadata[TagHelperBoundAttributeDescriptorBuilder.PropertyNameKey]}";
var propertyAccessor = $"{tagHelperVariableName}.{descriptor.GetPropertyName()}";
if (isIndexerNameMatch)
{

View File

@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration
string attributeName,
BoundAttributeDescriptor descriptor)
{
var propertyAccessor = $"{tagHelperVariableName}.{descriptor.Metadata[TagHelperBoundAttributeDescriptorBuilder.PropertyNameKey]}";
var propertyAccessor = $"{tagHelperVariableName}.{descriptor.GetPropertyName()}";
if (isIndexerNameMatch)
{

View File

@ -310,7 +310,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration
{
var tagHelperVariableName = GetTagHelperVariableName(node.TagHelperTypeName);
var tagHelperRenderingContext = context.TagHelperRenderingContext;
var propertyName = node.Descriptor.Metadata[TagHelperBoundAttributeDescriptorBuilder.PropertyNameKey];
var propertyName = node.Descriptor.GetPropertyName();
// Ensure that the property we're trying to set has initialized its dictionary bound properties.
if (node.IsIndexerNameMatch &&
@ -453,7 +453,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration
string attributeName,
BoundAttributeDescriptor descriptor)
{
var propertyAccessor = $"{tagHelperVariableName}.{descriptor.Metadata[TagHelperBoundAttributeDescriptorBuilder.PropertyNameKey]}";
var propertyAccessor = $"{tagHelperVariableName}.{descriptor.GetPropertyName()}";
if (isIndexerNameMatch)
{

View File

@ -533,7 +533,7 @@ namespace Microsoft.AspNetCore.Razor.Language
foreach (var descriptor in block.Binding.Descriptors)
{
var typeName = descriptor.Metadata[TagHelperDescriptorBuilder.TypeNameKey];
var typeName = descriptor.GetTypeName();
_tagHelperFields.UsedTagHelperTypeNames.Add(typeName);
}
}
@ -543,7 +543,7 @@ namespace Microsoft.AspNetCore.Razor.Language
var descriptors = tagHelperBinding.Descriptors;
foreach (var descriptor in descriptors)
{
var typeName = descriptor.Metadata[TagHelperDescriptorBuilder.TypeNameKey];
var typeName = descriptor.GetTypeName();
var createTagHelper = new CreateTagHelperIRNode()
{
TagHelperTypeName = typeName,
@ -577,8 +577,8 @@ namespace Microsoft.AspNetCore.Razor.Language
{
var associatedAttributeDescriptor = associatedDescriptor.BoundAttributes.First(
attributeDescriptor => TagHelperMatchingConventions.CanSatisfyBoundAttribute(attribute.Name, attributeDescriptor));
var tagHelperTypeName = associatedDescriptor.Metadata[TagHelperDescriptorBuilder.TypeNameKey];
var attributePropertyName = associatedAttributeDescriptor.Metadata[TagHelperBoundAttributeDescriptorBuilder.PropertyNameKey];
var tagHelperTypeName = associatedDescriptor.GetTypeName();
var attributePropertyName = associatedAttributeDescriptor.GetPropertyName();
var setTagHelperProperty = new SetTagHelperPropertyIRNode()
{

View File

@ -267,13 +267,13 @@ namespace Microsoft.AspNetCore.Razor.Language
return false;
}
if (descriptor.Kind != TagHelperDescriptorBuilder.DescriptorKind)
if (!descriptor.IsDefaultKind())
{
// We only understand TagHelperDescriptors generated from ITagHelpers.
// We only understand default TagHelperDescriptors.
return false;
}
var descriptorTypeName = descriptor.Metadata[TagHelperDescriptorBuilder.TypeNameKey];
var descriptorTypeName = descriptor.GetTypeName();
if (lookupInfo.TypePattern.EndsWith("*", StringComparison.Ordinal))
{

View File

@ -273,7 +273,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
if (invalidRule != null)
{
var typeName = descriptor.Metadata[TagHelperDescriptorBuilder.TypeNameKey];
var typeName = descriptor.GetTypeName();
// End tag TagHelper that states it shouldn't have an end tag.
errorSink.OnError(
@ -564,8 +564,8 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
// Can't have a set of TagHelpers that expect different structures.
if (baseStructure.HasValue && baseStructure != rule.TagStructure)
{
var baseDescriptorTypeName = baseDescriptor.Metadata[TagHelperDescriptorBuilder.TypeNameKey];
var descriptorTypeName = descriptor.Metadata[TagHelperDescriptorBuilder.TypeNameKey];
var baseDescriptorTypeName = baseDescriptor.GetTypeName();
var descriptorTypeName = descriptor.GetTypeName();
errorSink.OnError(
tagBlock.Start,
LegacyResources.FormatTagHelperParseTreeRewriter_InconsistentTagStructure(

View File

@ -9,8 +9,8 @@ namespace Microsoft.AspNetCore.Razor.Language
{
public sealed class TagHelperBoundAttributeDescriptorBuilder
{
public static readonly string DescriptorKind = "ITagHelper";
public static readonly string PropertyNameKey = "ITagHelper.PropertyName";
internal const string DescriptorKind = "ITagHelper";
internal const string PropertyNameKey = "ITagHelper.PropertyName";
private static readonly IReadOnlyDictionary<string, string> PrimitiveDisplayTypeNameLookups = new Dictionary<string, string>(StringComparer.Ordinal)
{

View File

@ -9,8 +9,8 @@ namespace Microsoft.AspNetCore.Razor.Language
{
public sealed class TagHelperDescriptorBuilder
{
public static readonly string DescriptorKind = "ITagHelper";
public static readonly string TypeNameKey = "ITagHelper.TypeName";
internal const string DescriptorKind = "ITagHelper";
internal const string TypeNameKey = "ITagHelper.TypeName";
private static ICollection<char> InvalidNonWhitespaceAllowedChildCharacters { get; } = new HashSet<char>(
new[] { '@', '!', '<', '/', '?', '[', '>', ']', '=', '"', '\'', '*' });

View File

@ -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 static class TagHelperDescriptorExtensions
{
public static string GetTypeName(this TagHelperDescriptor descriptor)
{
descriptor.Metadata.TryGetValue(TagHelperDescriptorBuilder.TypeNameKey, out var typeName);
return typeName;
}
public static bool IsDefaultKind(this TagHelperDescriptor descriptor)
=> string.Equals(descriptor.Kind, TagHelperDescriptorBuilder.DescriptorKind, StringComparison.Ordinal);
}
}

View File

@ -0,0 +1,81 @@
// 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 BoundAttributeDescriptorExtensionsTest
{
[Fact]
public void GetPropertyName_ReturnsPropertyName()
{
// Arrange
var expectedPropertyName = "IntProperty";
var descriptor = TagHelperBoundAttributeDescriptorBuilder.Create("TestTagHelper")
.Name("test")
.PropertyName(expectedPropertyName)
.TypeName(typeof(int).FullName)
.Build();
// Act
var propertyName = descriptor.GetPropertyName();
// Assert
Assert.Equal(expectedPropertyName, propertyName);
}
[Fact]
public void GetPropertyName_ReturnsNullIfNoPropertyName()
{
// Arrange
var descriptor = TagHelperBoundAttributeDescriptorBuilder.Create("TestTagHelper")
.Name("test")
.TypeName(typeof(int).FullName)
.Build();
// Act
var propertyName = descriptor.GetPropertyName();
// Assert
Assert.Null(propertyName);
}
[Fact]
public void IsDefaultKind_ReturnsTrueIfFromDefaultBuilder()
{
// Arrange
var descriptor = TagHelperBoundAttributeDescriptorBuilder.Create("TestTagHelper")
.Name("test")
.PropertyName("IntProperty")
.TypeName(typeof(int).FullName)
.Build();
// Act
var isDefault = descriptor.IsDefaultKind();
// Assert
Assert.True(isDefault);
}
[Fact]
public void IsDefaultKind_ReturnsFalseIfFromCustomBuilder()
{
// Arrange
var descriptor = new CustomBoundAttributeDescriptor();
// Act
var isDefault = descriptor.IsDefaultKind();
// Assert
Assert.False(isDefault);
}
private class CustomBoundAttributeDescriptor : BoundAttributeDescriptor
{
public CustomBoundAttributeDescriptor() : base("custom")
{
}
}
}
}

View File

@ -0,0 +1,72 @@
// 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;
using Xunit;
namespace Microsoft.AspNetCore.Razor.Language
{
public class TagHelperDescriptorExtensionsTest
{
[Fact]
public void GetTypeName_ReturnsTypeName()
{
// Arrange
var expectedTypeName = "TestTagHelper";
var descriptor = TagHelperDescriptorBuilder.Create(expectedTypeName, "TestAssembly").Build();
// Act
var typeName = descriptor.GetTypeName();
// Assert
Assert.Equal(expectedTypeName, typeName);
}
[Fact]
public void GetTypeName_ReturnsNullIfNoTypeName()
{
// Arrange
var descriptor = new CustomTagHelperDescriptor();
// Act
var typeName = descriptor.GetTypeName();
// Assert
Assert.Null(typeName);
}
[Fact]
public void IsDefaultKind_ReturnsTrueIfFromDefaultBuilder()
{
// Arrange
var descriptor = TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly").Build();
// Act
var isDefault = descriptor.IsDefaultKind();
// Assert
Assert.True(isDefault);
}
[Fact]
public void IsDefaultKind_ReturnsFalseIfFromCustomBuilder()
{
// Arrange
var descriptor = new CustomTagHelperDescriptor();
// Act
var isDefault = descriptor.IsDefaultKind();
// Assert
Assert.False(isDefault);
}
private class CustomTagHelperDescriptor : TagHelperDescriptor
{
public CustomTagHelperDescriptor() : base("custom")
{
Metadata = new Dictionary<string, string>();
}
}
}
}

View File

@ -20,7 +20,7 @@ namespace Microsoft.VisualStudio.RazorExtension.RazorInfo
public string TargetElement => string.Join(", ", _descriptor.TagMatchingRules.Select(rule => rule.TagName));
public string TypeName => _descriptor.Metadata[TagHelperDescriptorBuilder.TypeNameKey];
public string TypeName => _descriptor.GetTypeName();
}
}
#endif