Add `[HtmlAttributeName(..., DictionaryAttributePrefix="prefix")]` part 1
- related to #89 because we need more descriptor comparers in more places - separate `TagHelperAttributeDescriptorComparer` and `TypeBasedTagHelperDescriptorComparer` - encourages reuse and most will soon be used in multiple classes - add `null` checks to `EquivalenceComparer` - also give parameters better names nits: - use `<inheritdoc/>` in `TagHelperDescriptorComparer` - also give it an explicit constructor - make product comparers easier to subclass - base test `CaseSensitiveTagHelperAttributeDescriptorComparer` on product code
This commit is contained in:
parent
959616cb9c
commit
7dc0508c03
|
|
@ -20,9 +20,6 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
|
|||
internal static readonly string ScopeManagerVariableName = "__tagHelperScopeManager";
|
||||
internal static readonly string RunnerVariableName = "__tagHelperRunner";
|
||||
|
||||
private static readonly TagHelperAttributeDescriptorComparer AttributeDescriptorComparer =
|
||||
new TagHelperAttributeDescriptorComparer();
|
||||
|
||||
private readonly CSharpCodeWriter _writer;
|
||||
private readonly CodeBuilderContext _context;
|
||||
private readonly IChunkVisitor _bodyVisitor;
|
||||
|
|
@ -64,7 +61,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
|
|||
// multiple TargetElement attributes are on a TagHelper type and matches overlap for an HTML element.
|
||||
// Having more than one descriptor with the same TagHelper type results in generated code that runs
|
||||
// the same TagHelper X many times (instead of once) over a single HTML element.
|
||||
var tagHelperDescriptors = chunk.Descriptors.Distinct(TypeNameTagHelperDescriptorComparer.Default);
|
||||
var tagHelperDescriptors = chunk.Descriptors.Distinct(TypeBasedTagHelperDescriptorComparer.Default);
|
||||
|
||||
RenderBeginTagHelperScope(chunk.TagName, chunk.SelfClosing, chunk.Children);
|
||||
|
||||
|
|
@ -577,39 +574,5 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This class is used to compare tag helper attributes by comparing only the HTML attribute name.
|
||||
private class TagHelperAttributeDescriptorComparer : IEqualityComparer<TagHelperAttributeDescriptor>
|
||||
{
|
||||
public bool Equals(TagHelperAttributeDescriptor descriptorX, TagHelperAttributeDescriptor descriptorY)
|
||||
{
|
||||
return string.Equals(descriptorX.Name, descriptorY.Name, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public int GetHashCode(TagHelperAttributeDescriptor descriptor)
|
||||
{
|
||||
return StringComparer.OrdinalIgnoreCase.GetHashCode(descriptor.Name);
|
||||
}
|
||||
}
|
||||
|
||||
private class TypeNameTagHelperDescriptorComparer : IEqualityComparer<TagHelperDescriptor>
|
||||
{
|
||||
public static readonly TypeNameTagHelperDescriptorComparer Default =
|
||||
new TypeNameTagHelperDescriptorComparer();
|
||||
|
||||
private TypeNameTagHelperDescriptorComparer()
|
||||
{
|
||||
}
|
||||
|
||||
public bool Equals(TagHelperDescriptor descriptorX, TagHelperDescriptor descriptorY)
|
||||
{
|
||||
return string.Equals(descriptorX.TypeName, descriptorY.TypeName, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public int GetHashCode(TagHelperDescriptor descriptor)
|
||||
{
|
||||
return StringComparer.Ordinal.GetHashCode(descriptor.TypeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,19 +2,25 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Parser.SyntaxTree
|
||||
{
|
||||
internal class EquivalenceComparer : IEqualityComparer<SyntaxTreeNode>
|
||||
{
|
||||
public bool Equals(SyntaxTreeNode x, SyntaxTreeNode y)
|
||||
public bool Equals(SyntaxTreeNode nodeX, SyntaxTreeNode nodeY)
|
||||
{
|
||||
return x.EquivalentTo(y);
|
||||
if (nodeX == nodeY)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return nodeX != null && nodeX.EquivalentTo(nodeY);
|
||||
}
|
||||
|
||||
public int GetHashCode(SyntaxTreeNode obj)
|
||||
public int GetHashCode([NotNull] SyntaxTreeNode node)
|
||||
{
|
||||
return obj.GetEquivalenceHash();
|
||||
return node.GetEquivalenceHash();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -474,22 +474,5 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
|
|||
return htmlSymbol.Type == HtmlSymbolType.DoubleQuote ||
|
||||
htmlSymbol.Type == HtmlSymbolType.SingleQuote;
|
||||
}
|
||||
|
||||
// This class is used to compare tag helper attributes by comparing only the HTML attribute name.
|
||||
private class TagHelperAttributeDescriptorComparer : IEqualityComparer<TagHelperAttributeDescriptor>
|
||||
{
|
||||
public static readonly TagHelperAttributeDescriptorComparer Default =
|
||||
new TagHelperAttributeDescriptorComparer();
|
||||
|
||||
public bool Equals(TagHelperAttributeDescriptor descriptorX, TagHelperAttributeDescriptor descriptorY)
|
||||
{
|
||||
return string.Equals(descriptorX.Name, descriptorY.Name, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public int GetHashCode(TagHelperAttributeDescriptor descriptor)
|
||||
{
|
||||
return StringComparer.OrdinalIgnoreCase.GetHashCode(descriptor.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
// 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 Microsoft.Framework.Internal;
|
||||
using Microsoft.Internal.Web.Utils;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="IEqualityComparer{TagHelperAttributeDescriptor}"/> used to check equality between
|
||||
/// two <see cref="TagHelperAttributeDescriptor"/>s.
|
||||
/// </summary>
|
||||
public class TagHelperAttributeDescriptorComparer : IEqualityComparer<TagHelperAttributeDescriptor>
|
||||
{
|
||||
/// <summary>
|
||||
/// A default instance of the <see cref="TagHelperAttributeDescriptorComparer"/>.
|
||||
/// </summary>
|
||||
public static readonly TagHelperAttributeDescriptorComparer Default =
|
||||
new TagHelperAttributeDescriptorComparer();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="TagHelperAttributeDescriptorComparer"/> instance.
|
||||
/// </summary>
|
||||
protected TagHelperAttributeDescriptorComparer()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <remarks>
|
||||
/// Determines equality based on <see cref="TagHelperAttributeDescriptor.Name"/>,
|
||||
/// <see cref="TagHelperAttributeDescriptor.PropertyName"/>,
|
||||
/// and <see cref="TagHelperAttributeDescriptor.TypeName"/>.
|
||||
/// </remarks>
|
||||
public virtual bool Equals(TagHelperAttributeDescriptor descriptorX, TagHelperAttributeDescriptor descriptorY)
|
||||
{
|
||||
if (descriptorX == descriptorY)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return descriptorX != null &&
|
||||
string.Equals(descriptorX.Name, descriptorY.Name, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(descriptorX.PropertyName, descriptorY.PropertyName, StringComparison.Ordinal) &&
|
||||
string.Equals(descriptorX.TypeName, descriptorY.TypeName, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual int GetHashCode([NotNull] TagHelperAttributeDescriptor descriptor)
|
||||
{
|
||||
return HashCodeCombiner.Start()
|
||||
.Add(descriptor.Name, StringComparer.OrdinalIgnoreCase)
|
||||
.Add(descriptor.PropertyName, StringComparer.Ordinal)
|
||||
.Add(descriptor.TypeName, StringComparer.Ordinal)
|
||||
.CombinedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Microsoft.Internal.Web.Utils;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
||||
|
|
@ -20,43 +21,39 @@ namespace Microsoft.AspNet.Razor.TagHelpers
|
|||
public static readonly TagHelperDescriptorComparer Default = new TagHelperDescriptorComparer();
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the two given tag helpers are equal.
|
||||
/// Initializes a new <see cref="TagHelperDescriptorComparer"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="descriptorX">A <see cref="TagHelperDescriptor"/> to compare with the given
|
||||
/// <paramref name="descriptorY"/>.</param>
|
||||
/// <param name="descriptorY">A <see cref="TagHelperDescriptor"/> to compare with the given
|
||||
/// <paramref name="descriptorX"/>.</param>
|
||||
/// <returns><c>true</c> if <paramref name="descriptorX"/> and <paramref name="descriptorY"/> are equal,
|
||||
/// <c>false</c> otherwise.</returns>
|
||||
protected TagHelperDescriptorComparer()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <remarks>
|
||||
/// Determines equality based on <see cref="TagHelperDescriptor.TypeName"/>,
|
||||
/// <see cref="TagHelperDescriptor.AssemblyName"/>, <see cref="TagHelperDescriptor.TagName"/>,
|
||||
/// and <see cref="TagHelperDescriptor.RequiredAttributes"/>.
|
||||
/// </remarks>
|
||||
public bool Equals(TagHelperDescriptor descriptorX, TagHelperDescriptor descriptorY)
|
||||
public virtual bool Equals(TagHelperDescriptor descriptorX, TagHelperDescriptor descriptorY)
|
||||
{
|
||||
return string.Equals(descriptorX.TypeName, descriptorY.TypeName, StringComparison.Ordinal) &&
|
||||
string.Equals(descriptorX.TagName, descriptorY.TagName, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(descriptorX.AssemblyName, descriptorY.AssemblyName, StringComparison.Ordinal) &&
|
||||
Enumerable.SequenceEqual(
|
||||
descriptorX.RequiredAttributes.OrderBy(
|
||||
attribute => attribute,
|
||||
StringComparer.OrdinalIgnoreCase),
|
||||
descriptorY.RequiredAttributes.OrderBy(
|
||||
attribute => attribute,
|
||||
StringComparer.OrdinalIgnoreCase),
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
if (descriptorX == descriptorY)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return descriptorX != null &&
|
||||
string.Equals(descriptorX.TypeName, descriptorY.TypeName, StringComparison.Ordinal) &&
|
||||
string.Equals(descriptorX.TagName, descriptorY.TagName, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(descriptorX.AssemblyName, descriptorY.AssemblyName, StringComparison.Ordinal) &&
|
||||
Enumerable.SequenceEqual(
|
||||
descriptorX.RequiredAttributes.OrderBy(attribute => attribute, StringComparer.OrdinalIgnoreCase),
|
||||
descriptorY.RequiredAttributes.OrderBy(attribute => attribute, StringComparer.OrdinalIgnoreCase),
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an <see cref="int"/> value that uniquely identifies the given <see cref="TagHelperDescriptor"/>.
|
||||
/// </summary>
|
||||
/// <param name="descriptor">The <see cref="TagHelperDescriptor"/> to create a hash code for.</param>
|
||||
/// <returns>An <see cref="int"/> that uniquely identifies the given <paramref name="descriptor"/>.</returns>
|
||||
public int GetHashCode(TagHelperDescriptor descriptor)
|
||||
/// <inheritdoc />
|
||||
public virtual int GetHashCode([NotNull] TagHelperDescriptor descriptor)
|
||||
{
|
||||
var hashCodeCombiner = HashCodeCombiner
|
||||
.Start()
|
||||
var hashCodeCombiner = HashCodeCombiner.Start()
|
||||
.Add(descriptor.TypeName, StringComparer.Ordinal)
|
||||
.Add(descriptor.TagName, StringComparer.OrdinalIgnoreCase)
|
||||
.Add(descriptor.AssemblyName, StringComparer.Ordinal);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
// 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 Microsoft.Framework.Internal;
|
||||
using Microsoft.Internal.Web.Utils;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="IEqualityComparer{TagHelperDescriptor}"/> that checks equality between two
|
||||
/// <see cref="TagHelperDescriptor"/>s using only their <see cref="TagHelperDescriptor.AssemblyName"/>s and
|
||||
/// <see cref="TagHelperDescriptor.TypeName"/>s.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is intended for scenarios where Reflection-based information is all important i.e.
|
||||
/// <see cref="TagHelperDescriptor.RequiredAttributes"/>, <see cref="TagHelperDescriptor.TagName"/>, and related
|
||||
/// properties are not relevant.
|
||||
/// </remarks>
|
||||
public class TypeBasedTagHelperDescriptorComparer : IEqualityComparer<TagHelperDescriptor>
|
||||
{
|
||||
/// <summary>
|
||||
/// A default instance of the <see cref="TypeBasedTagHelperDescriptorComparer"/>.
|
||||
/// </summary>
|
||||
public static readonly TypeBasedTagHelperDescriptorComparer Default =
|
||||
new TypeBasedTagHelperDescriptorComparer();
|
||||
|
||||
private TypeBasedTagHelperDescriptorComparer()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <remarks>
|
||||
/// Determines equality based on <see cref="TagHelperDescriptor.AssemblyName"/> and
|
||||
/// <see cref="TagHelperDescriptor.TypeName"/>.
|
||||
/// </remarks>
|
||||
public bool Equals(TagHelperDescriptor descriptorX, TagHelperDescriptor descriptorY)
|
||||
{
|
||||
if (descriptorX == descriptorY)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return string.Equals(descriptorX.AssemblyName, descriptorY.AssemblyName, StringComparison.Ordinal) &&
|
||||
string.Equals(descriptorX.TypeName, descriptorY.TypeName, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int GetHashCode([NotNull] TagHelperDescriptor descriptor)
|
||||
{
|
||||
return HashCodeCombiner.Start()
|
||||
.Add(descriptor.AssemblyName, StringComparer.Ordinal)
|
||||
.Add(descriptor.TypeName, StringComparer.Ordinal)
|
||||
.CombinedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,37 +2,38 @@
|
|||
// 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 Microsoft.AspNet.Razor.TagHelpers;
|
||||
using Microsoft.Internal.Web.Utils;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||
{
|
||||
public class CaseSensitiveTagHelperAttributeDescriptorComparer : IEqualityComparer<TagHelperAttributeDescriptor>
|
||||
public class CaseSensitiveTagHelperAttributeDescriptorComparer : TagHelperAttributeDescriptorComparer
|
||||
{
|
||||
public static readonly CaseSensitiveTagHelperAttributeDescriptorComparer Default =
|
||||
public new static readonly CaseSensitiveTagHelperAttributeDescriptorComparer Default =
|
||||
new CaseSensitiveTagHelperAttributeDescriptorComparer();
|
||||
|
||||
private CaseSensitiveTagHelperAttributeDescriptorComparer()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
public bool Equals(TagHelperAttributeDescriptor descriptorX, TagHelperAttributeDescriptor descriptorY)
|
||||
public override bool Equals(TagHelperAttributeDescriptor descriptorX, TagHelperAttributeDescriptor descriptorY)
|
||||
{
|
||||
return
|
||||
if (descriptorX == descriptorY)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.Equals(descriptorX, descriptorY) &&
|
||||
// Normal comparer doesn't care about case, in tests we do.
|
||||
string.Equals(descriptorX.Name, descriptorY.Name, StringComparison.Ordinal) &&
|
||||
string.Equals(descriptorX.PropertyName, descriptorY.PropertyName, StringComparison.Ordinal) &&
|
||||
string.Equals(descriptorX.TypeName, descriptorY.TypeName, StringComparison.Ordinal);
|
||||
string.Equals(descriptorX.Name, descriptorY.Name, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public int GetHashCode(TagHelperAttributeDescriptor descriptor)
|
||||
public override int GetHashCode(TagHelperAttributeDescriptor descriptor)
|
||||
{
|
||||
return HashCodeCombiner
|
||||
.Start()
|
||||
return HashCodeCombiner.Start()
|
||||
.Add(base.GetHashCode(descriptor))
|
||||
.Add(descriptor.Name, StringComparer.Ordinal)
|
||||
.Add(descriptor.PropertyName, StringComparer.Ordinal)
|
||||
.Add(descriptor.TypeName, StringComparer.Ordinal)
|
||||
.CombinedHash;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,26 +2,29 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.Razor.TagHelpers;
|
||||
using Microsoft.Internal.Web.Utils;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||
{
|
||||
public class CaseSensitiveTagHelperDescriptorComparer : TagHelperDescriptorComparer, IEqualityComparer<TagHelperDescriptor>
|
||||
public class CaseSensitiveTagHelperDescriptorComparer : TagHelperDescriptorComparer
|
||||
{
|
||||
public new static readonly CaseSensitiveTagHelperDescriptorComparer Default =
|
||||
new CaseSensitiveTagHelperDescriptorComparer();
|
||||
|
||||
private CaseSensitiveTagHelperDescriptorComparer()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
bool IEqualityComparer<TagHelperDescriptor>.Equals(
|
||||
TagHelperDescriptor descriptorX,
|
||||
TagHelperDescriptor descriptorY)
|
||||
public override bool Equals(TagHelperDescriptor descriptorX, TagHelperDescriptor descriptorY)
|
||||
{
|
||||
if (descriptorX == descriptorY)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.Equals(descriptorX, descriptorY) &&
|
||||
// Normal comparer doesn't care about the case, required attribute order, attributes or prefixes.
|
||||
// In tests we do.
|
||||
|
|
@ -36,10 +39,9 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
CaseSensitiveTagHelperAttributeDescriptorComparer.Default);
|
||||
}
|
||||
|
||||
int IEqualityComparer<TagHelperDescriptor>.GetHashCode(TagHelperDescriptor descriptor)
|
||||
public override int GetHashCode(TagHelperDescriptor descriptor)
|
||||
{
|
||||
var hashCodeCombiner = HashCodeCombiner
|
||||
.Start()
|
||||
var hashCodeCombiner = HashCodeCombiner.Start()
|
||||
.Add(base.GetHashCode(descriptor))
|
||||
.Add(descriptor.TagName, StringComparer.Ordinal)
|
||||
.Add(descriptor.Prefix);
|
||||
|
|
|
|||
Loading…
Reference in New Issue