Add `TagHelperFactsService`.
- Add API to enable the editor to query information on the state of `TagHelper`s within a Razor document. - Refactored methods from `TagHelperDescriptorProvider` to be in a `TagHelperDescriptorConventions` class so the language service could use them. - Added `DefaultTagHelperFactService` tests. #1120
This commit is contained in:
parent
c1500da2a8
commit
22c7c90b5a
|
|
@ -530,7 +530,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
{
|
||||
var attributeValueNode = attribute.Value;
|
||||
var associatedDescriptors = descriptors.Where(descriptor =>
|
||||
descriptor.BoundAttributes.Any(attributeDescriptor => attributeDescriptor.CanMatchName(attribute.Name)));
|
||||
descriptor.BoundAttributes.Any(attributeDescriptor => TagHelperMatchingConventions.CanSatisfyBoundAttribute(attribute.Name, attributeDescriptor)));
|
||||
|
||||
if (associatedDescriptors.Any() && renderedBoundAttributeNames.Add(attribute.Name))
|
||||
{
|
||||
|
|
@ -544,7 +544,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
foreach (var associatedDescriptor in associatedDescriptors)
|
||||
{
|
||||
var associatedAttributeDescriptor = associatedDescriptor.BoundAttributes.First(
|
||||
attributeDescriptor => attributeDescriptor.CanMatchName(attribute.Name));
|
||||
attributeDescriptor => TagHelperMatchingConventions.CanSatisfyBoundAttribute(attribute.Name, attributeDescriptor));
|
||||
var tagHelperTypeName = associatedDescriptor.Metadata[ITagHelperDescriptorBuilder.TypeNameKey];
|
||||
var attributePropertyName = associatedAttributeDescriptor.Metadata[ITagHelperBoundAttributeDescriptorBuilder.PropertyNameKey];
|
||||
|
||||
|
|
@ -557,7 +557,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
Binding = tagHelperBinding,
|
||||
ValueStyle = attribute.ValueStyle,
|
||||
Source = BuildSourceSpanFromNode(attributeValueNode),
|
||||
IsIndexerNameMatch = associatedAttributeDescriptor.IsIndexerNameMatch(attribute.Name),
|
||||
IsIndexerNameMatch = TagHelperMatchingConventions.SatisfiesBoundAttributeIndexer(attribute.Name, associatedAttributeDescriptor),
|
||||
};
|
||||
|
||||
_builder.Push(setTagHelperProperty);
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
|
||||
yield return diagnostic;
|
||||
}
|
||||
else if (name != TagHelperDescriptorProvider.ElementCatchAllTarget)
|
||||
else if (name != TagHelperMatchingConventions.ElementCatchAllName)
|
||||
{
|
||||
foreach (var character in name)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -655,7 +655,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
private static string GetPropertyType(string name, IEnumerable<TagHelperDescriptor> descriptors)
|
||||
{
|
||||
var firstBoundAttribute = FindFirstBoundAttribute(name, descriptors);
|
||||
var isBoundToIndexer = firstBoundAttribute.IsIndexerNameMatch(name);
|
||||
var isBoundToIndexer = TagHelperMatchingConventions.SatisfiesBoundAttributeIndexer(name, firstBoundAttribute);
|
||||
|
||||
if (isBoundToIndexer)
|
||||
{
|
||||
|
|
@ -674,7 +674,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
var isBoundAttribute = firstBoundAttribute != null;
|
||||
var isBoundNonStringAttribute = isBoundAttribute &&
|
||||
!(firstBoundAttribute.IsStringProperty ||
|
||||
(firstBoundAttribute.IsIndexerNameMatch(name) && firstBoundAttribute.IsIndexerStringProperty));
|
||||
(TagHelperMatchingConventions.SatisfiesBoundAttributeIndexer(name, firstBoundAttribute) && firstBoundAttribute.IsIndexerStringProperty));
|
||||
var isMissingDictionaryKey = isBoundAttribute &&
|
||||
firstBoundAttribute.IndexerNamePrefix != null &&
|
||||
name.Length == firstBoundAttribute.IndexerNamePrefix.Length;
|
||||
|
|
@ -695,7 +695,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
{
|
||||
var firstBoundAttribute = descriptors
|
||||
.SelectMany(descriptor => descriptor.BoundAttributes)
|
||||
.FirstOrDefault(attributeDescriptor => attributeDescriptor.CanMatchName(name));
|
||||
.FirstOrDefault(attributeDescriptor => TagHelperMatchingConventions.CanSatisfyBoundAttribute(name, attributeDescriptor));
|
||||
|
||||
return firstBoundAttribute;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
/// </summary>
|
||||
internal class TagHelperDescriptorProvider
|
||||
{
|
||||
public const string ElementCatchAllTarget = "*";
|
||||
|
||||
private IDictionary<string, HashSet<TagHelperDescriptor>> _registrations;
|
||||
private readonly string _tagHelperPrefix;
|
||||
|
||||
|
|
@ -60,7 +58,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
IEnumerable<TagHelperDescriptor> descriptors;
|
||||
|
||||
// Ensure there's a HashSet to use.
|
||||
if (!_registrations.TryGetValue(ElementCatchAllTarget, out HashSet<TagHelperDescriptor> catchAllDescriptors))
|
||||
if (!_registrations.TryGetValue(TagHelperMatchingConventions.ElementCatchAllName, out HashSet<TagHelperDescriptor> catchAllDescriptors))
|
||||
{
|
||||
descriptors = new HashSet<TagHelperDescriptor>(TagHelperDescriptorComparer.Default);
|
||||
}
|
||||
|
|
@ -81,7 +79,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
foreach (var descriptor in descriptors)
|
||||
{
|
||||
var applicableRules = descriptor.TagMatchingRules.Where(
|
||||
rule => MatchesRule(rule, attributes, tagNameWithoutPrefix, parentTagName));
|
||||
rule => TagHelperMatchingConventions.SatisfiesRule(tagNameWithoutPrefix, parentTagName, attributes, rule));
|
||||
|
||||
if (applicableRules.Any())
|
||||
{
|
||||
|
|
@ -104,43 +102,13 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
return tagMappingResult;
|
||||
}
|
||||
|
||||
private bool MatchesRule(
|
||||
TagMatchingRule rule,
|
||||
IEnumerable<KeyValuePair<string, string>> tagAttributes,
|
||||
string tagNameWithoutPrefix,
|
||||
string parentTagName)
|
||||
{
|
||||
// Verify tag name
|
||||
if (rule.TagName != ElementCatchAllTarget &&
|
||||
rule.TagName != null &&
|
||||
!string.Equals(tagNameWithoutPrefix, rule.TagName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify parent tag
|
||||
if (rule.ParentTag != null && !string.Equals(parentTagName, rule.ParentTag, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!rule.Attributes.All(
|
||||
requiredAttribute => tagAttributes.Any(
|
||||
attribute => requiredAttribute.IsMatch(attribute.Key, attribute.Value))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Register(TagHelperDescriptor descriptor)
|
||||
{
|
||||
foreach (var rule in descriptor.TagMatchingRules)
|
||||
{
|
||||
var registrationKey =
|
||||
string.Equals(rule.TagName, ElementCatchAllTarget, StringComparison.Ordinal) ?
|
||||
ElementCatchAllTarget :
|
||||
string.Equals(rule.TagName, TagHelperMatchingConventions.ElementCatchAllName, StringComparison.Ordinal) ?
|
||||
TagHelperMatchingConventions.ElementCatchAllName :
|
||||
_tagHelperPrefix + rule.TagName;
|
||||
|
||||
// Ensure there's a HashSet to add the descriptor to.
|
||||
|
|
|
|||
|
|
@ -1,67 +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 System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Evolution
|
||||
{
|
||||
internal static class TagHelperDescriptorMatchingConventions
|
||||
{
|
||||
public static bool CanMatchName(this BoundAttributeDescriptor descriptor, string name)
|
||||
{
|
||||
return IsFullNameMatch(descriptor, name) || IsIndexerNameMatch(descriptor, name);
|
||||
}
|
||||
|
||||
public static bool IsFullNameMatch(this BoundAttributeDescriptor descriptor, string name)
|
||||
{
|
||||
return string.Equals(descriptor.Name, name, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public static bool IsIndexerNameMatch(this BoundAttributeDescriptor descriptor, string name)
|
||||
{
|
||||
return descriptor.IndexerNamePrefix != null &&
|
||||
!IsFullNameMatch(descriptor, name) &&
|
||||
name.StartsWith(descriptor.IndexerNamePrefix, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public static bool IsMatch(this RequiredAttributeDescriptor descriptor, string attributeName, string attributeValue)
|
||||
{
|
||||
var nameMatches = false;
|
||||
if (descriptor.NameComparison == RequiredAttributeDescriptor.NameComparisonMode.FullMatch)
|
||||
{
|
||||
nameMatches = string.Equals(descriptor.Name, attributeName, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
else if (descriptor.NameComparison == RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch)
|
||||
{
|
||||
// attributeName cannot equal the Name if comparing as a PrefixMatch.
|
||||
nameMatches = attributeName.Length != descriptor.Name.Length &&
|
||||
attributeName.StartsWith(descriptor.Name, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(false, "Unknown name comparison.");
|
||||
}
|
||||
|
||||
if (!nameMatches)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (descriptor.ValueComparison)
|
||||
{
|
||||
case RequiredAttributeDescriptor.ValueComparisonMode.None:
|
||||
return true;
|
||||
case RequiredAttributeDescriptor.ValueComparisonMode.PrefixMatch: // Value starts with
|
||||
return attributeValue.StartsWith(descriptor.Value, StringComparison.Ordinal);
|
||||
case RequiredAttributeDescriptor.ValueComparisonMode.SuffixMatch: // Value ends with
|
||||
return attributeValue.EndsWith(descriptor.Value, StringComparison.Ordinal);
|
||||
case RequiredAttributeDescriptor.ValueComparisonMode.FullMatch: // Value equals
|
||||
return string.Equals(attributeValue, descriptor.Value, StringComparison.Ordinal);
|
||||
default:
|
||||
Debug.Assert(false, "Unknown value comparison.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
// 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.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Evolution
|
||||
{
|
||||
internal static class TagHelperMatchingConventions
|
||||
{
|
||||
public const string ElementCatchAllName = "*";
|
||||
|
||||
public static bool SatisfiesRule(
|
||||
string tagNameWithoutPrefix,
|
||||
string parentTagName,
|
||||
IEnumerable<KeyValuePair<string, string>> tagAttributes,
|
||||
TagMatchingRule rule)
|
||||
{
|
||||
if (tagNameWithoutPrefix == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tagNameWithoutPrefix));
|
||||
}
|
||||
|
||||
if (tagAttributes == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tagAttributes));
|
||||
}
|
||||
|
||||
if (rule == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(rule));
|
||||
}
|
||||
|
||||
var satisfiesTagName = SatisfiesTagName(tagNameWithoutPrefix, rule);
|
||||
if (!satisfiesTagName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var satisfiesParentTag = SatisfiesParentTag(parentTagName, rule);
|
||||
if (!satisfiesParentTag)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var satisfiesAttributes = SatisfiesAttributes(tagAttributes, rule);
|
||||
if (!satisfiesAttributes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool SatisfiesTagName(string tagNameWithoutPrefix, TagMatchingRule rule)
|
||||
{
|
||||
if (tagNameWithoutPrefix == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tagNameWithoutPrefix));
|
||||
}
|
||||
|
||||
if (rule == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(rule));
|
||||
}
|
||||
|
||||
if (rule.TagName != ElementCatchAllName &&
|
||||
rule.TagName != null &&
|
||||
!string.Equals(tagNameWithoutPrefix, rule.TagName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool SatisfiesParentTag(string parentTagName, TagMatchingRule rule)
|
||||
{
|
||||
if (rule == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(rule));
|
||||
}
|
||||
|
||||
if (rule.ParentTag != null && !string.Equals(parentTagName, rule.ParentTag, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool SatisfiesAttributes(IEnumerable<KeyValuePair<string, string>> tagAttributes, TagMatchingRule rule)
|
||||
{
|
||||
if (tagAttributes == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tagAttributes));
|
||||
}
|
||||
|
||||
if (rule == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(rule));
|
||||
}
|
||||
|
||||
if (!rule.Attributes.All(
|
||||
requiredAttribute => tagAttributes.Any(
|
||||
attribute => SatisfiesRequiredAttribute(attribute.Key, attribute.Value, requiredAttribute))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool CanSatisfyBoundAttribute(string name, BoundAttributeDescriptor descriptor)
|
||||
{
|
||||
return SatisfiesBoundAttributeName(name, descriptor) || SatisfiesBoundAttributeIndexer(name, descriptor);
|
||||
}
|
||||
|
||||
public static bool SatisfiesBoundAttributeIndexer(string name, BoundAttributeDescriptor descriptor)
|
||||
{
|
||||
return descriptor.IndexerNamePrefix != null &&
|
||||
!SatisfiesBoundAttributeName(name, descriptor) &&
|
||||
name.StartsWith(descriptor.IndexerNamePrefix, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static bool SatisfiesBoundAttributeName(string name, BoundAttributeDescriptor descriptor)
|
||||
{
|
||||
return string.Equals(descriptor.Name, name, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
// Internal for testing
|
||||
internal static bool SatisfiesRequiredAttribute(string attributeName, string attributeValue, RequiredAttributeDescriptor descriptor)
|
||||
{
|
||||
var nameMatches = false;
|
||||
if (descriptor.NameComparison == RequiredAttributeDescriptor.NameComparisonMode.FullMatch)
|
||||
{
|
||||
nameMatches = string.Equals(descriptor.Name, attributeName, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
else if (descriptor.NameComparison == RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch)
|
||||
{
|
||||
// attributeName cannot equal the Name if comparing as a PrefixMatch.
|
||||
nameMatches = attributeName.Length != descriptor.Name.Length &&
|
||||
attributeName.StartsWith(descriptor.Name, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(false, "Unknown name comparison.");
|
||||
}
|
||||
|
||||
if (!nameMatches)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (descriptor.ValueComparison)
|
||||
{
|
||||
case RequiredAttributeDescriptor.ValueComparisonMode.None:
|
||||
return true;
|
||||
case RequiredAttributeDescriptor.ValueComparisonMode.PrefixMatch: // Value starts with
|
||||
return attributeValue.StartsWith(descriptor.Value, StringComparison.Ordinal);
|
||||
case RequiredAttributeDescriptor.ValueComparisonMode.SuffixMatch: // Value ends with
|
||||
return attributeValue.EndsWith(descriptor.Value, StringComparison.Ordinal);
|
||||
case RequiredAttributeDescriptor.ValueComparisonMode.FullMatch: // Value equals
|
||||
return string.Equals(attributeValue, descriptor.Value, StringComparison.Ordinal);
|
||||
default:
|
||||
Debug.Assert(false, "Unknown value comparison.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
|
||||
yield return diagnostic;
|
||||
}
|
||||
else if (_tagName != TagHelperDescriptorProvider.ElementCatchAllTarget)
|
||||
else if (_tagName != TagHelperMatchingConventions.ElementCatchAllName)
|
||||
{
|
||||
foreach (var character in _tagName)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -371,7 +371,7 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
{
|
||||
if (attibute.ConstructorArguments.Length == 0)
|
||||
{
|
||||
return TagHelperDescriptorProvider.ElementCatchAllTarget;
|
||||
return TagHelperMatchingConventions.ElementCatchAllName;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,12 +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 System.ComponentModel.Composition;
|
||||
|
||||
namespace Microsoft.VisualStudio.LanguageServices.Razor
|
||||
{
|
||||
[Export(typeof(RazorTagHelperFactsService))]
|
||||
internal class DefaultRazorTagHelperFactsService : RazorTagHelperFactsService
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
// 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.Evolution;
|
||||
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.VisualStudio.LanguageServices.Razor
|
||||
{
|
||||
[Export(typeof(TagHelperFactsService))]
|
||||
internal class DefaultTagHelperFactsService : TagHelperFactsService
|
||||
{
|
||||
public override TagHelperBinding GetTagHelperBinding(
|
||||
TagHelperDocumentContext documentContext,
|
||||
string tagName,
|
||||
IEnumerable<KeyValuePair<string, string>> attributes,
|
||||
string parentTag)
|
||||
{
|
||||
if (documentContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(documentContext));
|
||||
}
|
||||
|
||||
if (tagName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tagName));
|
||||
}
|
||||
|
||||
if (attributes == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(attributes));
|
||||
}
|
||||
|
||||
var descriptors = documentContext.TagHelpers;
|
||||
if (descriptors == null || descriptors.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var prefix = documentContext.Prefix;
|
||||
var provider = new TagHelperDescriptorProvider(prefix, descriptors);
|
||||
var binding = provider.GetTagHelperBinding(tagName, attributes, parentTag);
|
||||
|
||||
return binding;
|
||||
}
|
||||
|
||||
public override IEnumerable<BoundAttributeDescriptor> GetBoundTagHelperAttributes(
|
||||
TagHelperDocumentContext documentContext,
|
||||
string attributeName,
|
||||
TagHelperBinding binding)
|
||||
{
|
||||
if (documentContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(documentContext));
|
||||
}
|
||||
|
||||
if (attributeName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(attributeName));
|
||||
}
|
||||
|
||||
if (binding == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(binding));
|
||||
}
|
||||
|
||||
var matchingBoundAttributes = new List<BoundAttributeDescriptor>();
|
||||
foreach (var descriptor in binding.Descriptors)
|
||||
{
|
||||
foreach (var boundAttributeDescriptor in descriptor.BoundAttributes)
|
||||
{
|
||||
if (TagHelperMatchingConventions.CanSatisfyBoundAttribute(attributeName, boundAttributeDescriptor))
|
||||
{
|
||||
matchingBoundAttributes.Add(boundAttributeDescriptor);
|
||||
|
||||
// Only one bound attribute can match an attribute
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matchingBoundAttributes;
|
||||
}
|
||||
|
||||
public override IReadOnlyList<TagHelperDescriptor> GetTagHelpersGivenTag(
|
||||
TagHelperDocumentContext documentContext,
|
||||
string tagName,
|
||||
string parentTag)
|
||||
{
|
||||
if (documentContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(documentContext));
|
||||
}
|
||||
|
||||
if (tagName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tagName));
|
||||
}
|
||||
|
||||
var matchingDescriptors = new List<TagHelperDescriptor>();
|
||||
var descriptors = documentContext?.TagHelpers;
|
||||
if (descriptors?.Count == 0)
|
||||
{
|
||||
return matchingDescriptors;
|
||||
}
|
||||
|
||||
var prefix = documentContext.Prefix ?? string.Empty;
|
||||
if (!tagName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Can't possibly match TagHelpers, it doesn't start with the TagHelperPrefix.
|
||||
return matchingDescriptors;
|
||||
}
|
||||
|
||||
var tagNameWithoutPrefix = tagName.Substring(prefix.Length);
|
||||
for (var i = 0; i < descriptors.Count; i++)
|
||||
{
|
||||
var descriptor = descriptors[i];
|
||||
foreach (var rule in descriptor.TagMatchingRules)
|
||||
{
|
||||
if (TagHelperMatchingConventions.SatisfiesTagName(tagNameWithoutPrefix, rule) &&
|
||||
TagHelperMatchingConventions.SatisfiesParentTag(parentTag, rule))
|
||||
{
|
||||
matchingDescriptors.Add(descriptor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matchingDescriptors;
|
||||
}
|
||||
|
||||
public override IReadOnlyList<TagHelperDescriptor> GetTagHelpersGivenParent(TagHelperDocumentContext documentContext, string parentTag)
|
||||
{
|
||||
if (documentContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(documentContext));
|
||||
}
|
||||
|
||||
if (parentTag == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(parentTag));
|
||||
}
|
||||
|
||||
var matchingDescriptors = new List<TagHelperDescriptor>();
|
||||
var descriptors = documentContext?.TagHelpers;
|
||||
if (descriptors?.Count == 0)
|
||||
{
|
||||
return matchingDescriptors;
|
||||
}
|
||||
|
||||
for (var i = 0; i < descriptors.Count; i++)
|
||||
{
|
||||
var descriptor = descriptors[i];
|
||||
foreach (var rule in descriptor.TagMatchingRules)
|
||||
{
|
||||
if (TagHelperMatchingConventions.SatisfiesParentTag(parentTag, rule))
|
||||
{
|
||||
matchingDescriptors.Add(descriptor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matchingDescriptors;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +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.
|
||||
|
||||
namespace Microsoft.VisualStudio.LanguageServices.Razor
|
||||
{
|
||||
public abstract class RazorTagHelperFactsService
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -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 Microsoft.AspNetCore.Razor.Evolution;
|
||||
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.VisualStudio.LanguageServices.Razor
|
||||
{
|
||||
public abstract class TagHelperFactsService
|
||||
{
|
||||
public abstract TagHelperBinding GetTagHelperBinding(TagHelperDocumentContext documentContext, string tagName, IEnumerable<KeyValuePair<string, string>> attributes, string parentTag);
|
||||
|
||||
public abstract IEnumerable<BoundAttributeDescriptor> GetBoundTagHelperAttributes(TagHelperDocumentContext documentContext, string attributeName, TagHelperBinding binding);
|
||||
|
||||
public abstract IReadOnlyList<TagHelperDescriptor> GetTagHelpersGivenTag(TagHelperDocumentContext documentContext, string tagName, string parentTag);
|
||||
|
||||
public abstract IReadOnlyList<TagHelperDescriptor> GetTagHelpersGivenParent(TagHelperDocumentContext documentContext, string parentTag);
|
||||
}
|
||||
}
|
||||
|
|
@ -115,20 +115,20 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
var catchAllDescriptor = ITagHelperDescriptorBuilder.Create("CatchAllTagHelper", "SomeAssembly")
|
||||
.TagMatchingRule(rule =>
|
||||
rule
|
||||
.RequireTagName(TagHelperDescriptorProvider.ElementCatchAllTarget)
|
||||
.RequireTagName(TagHelperMatchingConventions.ElementCatchAllName)
|
||||
.RequireAttribute(attribute => attribute.Name("class")))
|
||||
.Build();
|
||||
var catchAllDescriptor2 = ITagHelperDescriptorBuilder.Create("CatchAllTagHelper2", "SomeAssembly")
|
||||
.TagMatchingRule(rule =>
|
||||
rule
|
||||
.RequireTagName(TagHelperDescriptorProvider.ElementCatchAllTarget)
|
||||
.RequireTagName(TagHelperMatchingConventions.ElementCatchAllName)
|
||||
.RequireAttribute(attribute => attribute.Name("custom"))
|
||||
.RequireAttribute(attribute => attribute.Name("class")))
|
||||
.Build();
|
||||
var catchAllWildcardPrefixDescriptor = ITagHelperDescriptorBuilder.Create("CatchAllWildCardAttribute", "SomeAssembly")
|
||||
.TagMatchingRule(rule =>
|
||||
rule
|
||||
.RequireTagName(TagHelperDescriptorProvider.ElementCatchAllTarget)
|
||||
.RequireTagName(TagHelperMatchingConventions.ElementCatchAllName)
|
||||
.RequireAttribute(attribute =>
|
||||
attribute
|
||||
.Name("prefix-")
|
||||
|
|
@ -254,7 +254,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
{
|
||||
// Arrange
|
||||
var catchAllDescriptor = ITagHelperDescriptorBuilder.Create("foo1", "SomeAssembly")
|
||||
.TagMatchingRule(rule => rule.RequireTagName(TagHelperDescriptorProvider.ElementCatchAllTarget))
|
||||
.TagMatchingRule(rule => rule.RequireTagName(TagHelperMatchingConventions.ElementCatchAllName))
|
||||
.Build();
|
||||
var descriptors = new[] { catchAllDescriptor };
|
||||
var provider = new TagHelperDescriptorProvider("th", descriptors);
|
||||
|
|
@ -274,7 +274,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
{
|
||||
// Arrange
|
||||
var catchAllDescriptor = ITagHelperDescriptorBuilder.Create("foo1", "SomeAssembly")
|
||||
.TagMatchingRule(rule => rule.RequireTagName(TagHelperDescriptorProvider.ElementCatchAllTarget))
|
||||
.TagMatchingRule(rule => rule.RequireTagName(TagHelperMatchingConventions.ElementCatchAllName))
|
||||
.Build();
|
||||
var descriptors = new[] { catchAllDescriptor };
|
||||
var provider = new TagHelperDescriptorProvider("th:", descriptors);
|
||||
|
|
@ -373,7 +373,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
.TagMatchingRule(rule => rule.RequireTagName("span"))
|
||||
.Build();
|
||||
var catchAllDescriptor = ITagHelperDescriptorBuilder.Create("foo3", "SomeAssembly")
|
||||
.TagMatchingRule(rule => rule.RequireTagName(TagHelperDescriptorProvider.ElementCatchAllTarget))
|
||||
.TagMatchingRule(rule => rule.RequireTagName(TagHelperMatchingConventions.ElementCatchAllName))
|
||||
.Build();
|
||||
var descriptors = new TagHelperDescriptor[] { divDescriptor, spanDescriptor, catchAllDescriptor };
|
||||
var provider = new TagHelperDescriptorProvider(null, descriptors);
|
||||
|
|
@ -427,7 +427,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
// Arrange
|
||||
var multiRuleDescriptor = ITagHelperDescriptorBuilder.Create("foo", "SomeAssembly")
|
||||
.TagMatchingRule(rule => rule
|
||||
.RequireTagName(TagHelperDescriptorProvider.ElementCatchAllTarget)
|
||||
.RequireTagName(TagHelperMatchingConventions.ElementCatchAllName)
|
||||
.RequireParentTag("body"))
|
||||
.TagMatchingRule(rule => rule
|
||||
.RequireTagName("div"))
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
bool expectedResult)
|
||||
{
|
||||
// Act
|
||||
var result = ((RequiredAttributeDescriptor)requiredAttributeDescriptor).IsMatch(attributeName, attributeValue);
|
||||
var result = TagHelperMatchingConventions.SatisfiesRequiredAttribute(attributeName, attributeValue, (RequiredAttributeDescriptor)requiredAttributeDescriptor);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedResult, result);
|
||||
|
|
|
|||
|
|
@ -720,7 +720,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces
|
|||
{
|
||||
typeof(AttributeTargetingTagHelper),
|
||||
CreateTagHelperDescriptor(
|
||||
TagHelperDescriptorProvider.ElementCatchAllTarget,
|
||||
TagHelperMatchingConventions.ElementCatchAllName,
|
||||
typeof(AttributeTargetingTagHelper).FullName,
|
||||
AssemblyName,
|
||||
ruleBuilders: new Action<TagMatchingRuleBuilder>[]
|
||||
|
|
@ -731,7 +731,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces
|
|||
{
|
||||
typeof(MultiAttributeTargetingTagHelper),
|
||||
CreateTagHelperDescriptor(
|
||||
TagHelperDescriptorProvider.ElementCatchAllTarget,
|
||||
TagHelperMatchingConventions.ElementCatchAllName,
|
||||
typeof(MultiAttributeTargetingTagHelper).FullName,
|
||||
AssemblyName,
|
||||
ruleBuilders: new Action<TagMatchingRuleBuilder>[]
|
||||
|
|
@ -747,7 +747,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces
|
|||
{
|
||||
typeof(MultiAttributeAttributeTargetingTagHelper),
|
||||
CreateTagHelperDescriptor(
|
||||
TagHelperDescriptorProvider.ElementCatchAllTarget,
|
||||
TagHelperMatchingConventions.ElementCatchAllName,
|
||||
typeof(MultiAttributeAttributeTargetingTagHelper).FullName,
|
||||
AssemblyName,
|
||||
ruleBuilders: new Action<TagMatchingRuleBuilder>[]
|
||||
|
|
@ -764,7 +764,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces
|
|||
{
|
||||
typeof(InheritedAttributeTargetingTagHelper),
|
||||
CreateTagHelperDescriptor(
|
||||
TagHelperDescriptorProvider.ElementCatchAllTarget,
|
||||
TagHelperMatchingConventions.ElementCatchAllName,
|
||||
typeof(InheritedAttributeTargetingTagHelper).FullName,
|
||||
AssemblyName,
|
||||
ruleBuilders: new Action<TagMatchingRuleBuilder>[]
|
||||
|
|
@ -856,7 +856,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces
|
|||
{
|
||||
typeof(AttributeWildcardTargetingTagHelper),
|
||||
CreateTagHelperDescriptor(
|
||||
TagHelperDescriptorProvider.ElementCatchAllTarget,
|
||||
TagHelperMatchingConventions.ElementCatchAllName,
|
||||
typeof(AttributeWildcardTargetingTagHelper).FullName,
|
||||
AssemblyName,
|
||||
ruleBuilders: new Action<TagMatchingRuleBuilder>[]
|
||||
|
|
@ -870,7 +870,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces
|
|||
{
|
||||
typeof(MultiAttributeWildcardTargetingTagHelper),
|
||||
CreateTagHelperDescriptor(
|
||||
TagHelperDescriptorProvider.ElementCatchAllTarget,
|
||||
TagHelperMatchingConventions.ElementCatchAllName,
|
||||
typeof(MultiAttributeWildcardTargetingTagHelper).FullName,
|
||||
AssemblyName,
|
||||
ruleBuilders: new Action<TagMatchingRuleBuilder>[]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,302 @@
|
|||
// 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.Evolution;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.VisualStudio.LanguageServices.Razor
|
||||
{
|
||||
public class DefaultTagHelperFactsServiceTest
|
||||
{
|
||||
// Purposefully not thoroughly testing DefaultTagHelperFactsService.GetTagHelperBinding because it's a pass through
|
||||
// into TagHelperDescriptorProvider.GetTagHelperBinding.
|
||||
|
||||
[Fact]
|
||||
public void GetTagHelperBinding_WorksAsExpected()
|
||||
{
|
||||
// Arrange
|
||||
var documentDescriptors = new[]
|
||||
{
|
||||
ITagHelperDescriptorBuilder.Create("TestType", "TestAssembly")
|
||||
.TagMatchingRule(rule =>
|
||||
rule
|
||||
.RequireTagName("a")
|
||||
.RequireAttribute(attribute => attribute.Name("asp-for")))
|
||||
.BindAttribute(attribute =>
|
||||
attribute
|
||||
.Name("asp-for")
|
||||
.TypeName(typeof(string).FullName)
|
||||
.PropertyName("AspFor"))
|
||||
.BindAttribute(attribute =>
|
||||
attribute
|
||||
.Name("asp-route")
|
||||
.TypeName(typeof(IDictionary<string, string>).Namespace + "IDictionary<string, string>")
|
||||
.PropertyName("AspRoute")
|
||||
.AsDictionary("asp-route-", typeof(string).FullName))
|
||||
.Build(),
|
||||
ITagHelperDescriptorBuilder.Create("TestType", "TestAssembly")
|
||||
.TagMatchingRule(rule => rule.RequireTagName("input"))
|
||||
.BindAttribute(attribute =>
|
||||
attribute
|
||||
.Name("asp-for")
|
||||
.TypeName(typeof(string).FullName)
|
||||
.PropertyName("AspFor"))
|
||||
.Build(),
|
||||
};
|
||||
var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors);
|
||||
var service = new DefaultTagHelperFactsService();
|
||||
var attributes = new[]
|
||||
{
|
||||
new KeyValuePair<string, string>("asp-for", "Name")
|
||||
};
|
||||
|
||||
// Act
|
||||
var binding = service.GetTagHelperBinding(documentContext, "a", attributes, parentTag: "p");
|
||||
|
||||
// Assert
|
||||
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);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetBoundTagHelperAttributes_MatchesPrefixedAttributeName()
|
||||
{
|
||||
// Arrange
|
||||
var documentDescriptors = new[]
|
||||
{
|
||||
ITagHelperDescriptorBuilder.Create("TestType", "TestAssembly")
|
||||
.TagMatchingRule(rule => rule.RequireTagName("a"))
|
||||
.BindAttribute(attribute =>
|
||||
attribute
|
||||
.Name("asp-for")
|
||||
.TypeName(typeof(string).FullName)
|
||||
.PropertyName("AspFor"))
|
||||
.BindAttribute(attribute =>
|
||||
attribute
|
||||
.Name("asp-route")
|
||||
.TypeName(typeof(IDictionary<string, string>).Namespace + "IDictionary<string, string>")
|
||||
.PropertyName("AspRoute")
|
||||
.AsDictionary("asp-route-", typeof(string).FullName))
|
||||
.Build()
|
||||
};
|
||||
var expectedAttributeDescriptors = new[]
|
||||
{
|
||||
documentDescriptors[0].BoundAttributes.Last()
|
||||
};
|
||||
var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors);
|
||||
var service = new DefaultTagHelperFactsService();
|
||||
var binding = service.GetTagHelperBinding(documentContext, "a", Enumerable.Empty<KeyValuePair<string, string>>(), parentTag: null);
|
||||
|
||||
// Act
|
||||
var descriptors = service.GetBoundTagHelperAttributes(documentContext, "asp-route-something", binding);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedAttributeDescriptors, descriptors, BoundAttributeDescriptorComparer.CaseSensitive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetBoundTagHelperAttributes_MatchesAttributeName()
|
||||
{
|
||||
// Arrange
|
||||
var documentDescriptors = new[]
|
||||
{
|
||||
ITagHelperDescriptorBuilder.Create("TestType", "TestAssembly")
|
||||
.TagMatchingRule(rule => rule.RequireTagName("input"))
|
||||
.BindAttribute(attribute =>
|
||||
attribute
|
||||
.Name("asp-for")
|
||||
.TypeName(typeof(string).FullName)
|
||||
.PropertyName("AspFor"))
|
||||
.BindAttribute(attribute =>
|
||||
attribute
|
||||
.Name("asp-extra")
|
||||
.TypeName(typeof(string).FullName)
|
||||
.PropertyName("AspExtra"))
|
||||
.Build()
|
||||
};
|
||||
var expectedAttributeDescriptors = new[]
|
||||
{
|
||||
documentDescriptors[0].BoundAttributes.First()
|
||||
};
|
||||
var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors);
|
||||
var service = new DefaultTagHelperFactsService();
|
||||
var binding = service.GetTagHelperBinding(documentContext, "input", Enumerable.Empty<KeyValuePair<string, string>>(), parentTag: null);
|
||||
|
||||
// Act
|
||||
var descriptors = service.GetBoundTagHelperAttributes(documentContext, "asp-for", binding);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedAttributeDescriptors, descriptors, BoundAttributeDescriptorComparer.CaseSensitive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTagHelpersGivenTag_RequiresTagName()
|
||||
{
|
||||
// Arrange
|
||||
var documentDescriptors = new[]
|
||||
{
|
||||
ITagHelperDescriptorBuilder.Create("TestType", "TestAssembly")
|
||||
.TagMatchingRule(rule => rule.RequireTagName("strong"))
|
||||
.Build()
|
||||
};
|
||||
var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors);
|
||||
var service = new DefaultTagHelperFactsService();
|
||||
|
||||
// Act
|
||||
var descriptors = service.GetTagHelpersGivenTag(documentContext, "strong", "p");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(documentDescriptors, descriptors, TagHelperDescriptorComparer.CaseSensitive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTagHelpersGivenTag_RestrictsTagHelpersBasedOnTagName()
|
||||
{
|
||||
// Arrange
|
||||
var expectedDescriptors = new[]
|
||||
{
|
||||
ITagHelperDescriptorBuilder.Create("TestType", "TestAssembly")
|
||||
.TagMatchingRule(
|
||||
rule => rule
|
||||
.RequireTagName("a")
|
||||
.RequireParentTag("div"))
|
||||
.Build()
|
||||
};
|
||||
var documentDescriptors = new[]
|
||||
{
|
||||
expectedDescriptors[0],
|
||||
ITagHelperDescriptorBuilder.Create("TestType2", "TestAssembly")
|
||||
.TagMatchingRule(
|
||||
rule => rule
|
||||
.RequireTagName("strong")
|
||||
.RequireParentTag("div"))
|
||||
.Build()
|
||||
};
|
||||
var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors);
|
||||
var service = new DefaultTagHelperFactsService();
|
||||
|
||||
// Act
|
||||
var descriptors = service.GetTagHelpersGivenTag(documentContext, "a", "div");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedDescriptors, descriptors, TagHelperDescriptorComparer.CaseSensitive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTagHelpersGivenTag_RestrictsTagHelpersBasedOnTagHelperPrefix()
|
||||
{
|
||||
// Arrange
|
||||
var expectedDescriptors = new[]
|
||||
{
|
||||
ITagHelperDescriptorBuilder.Create("TestType", "TestAssembly")
|
||||
.TagMatchingRule(rule => rule.RequireTagName("strong"))
|
||||
.Build()
|
||||
};
|
||||
var documentDescriptors = new[]
|
||||
{
|
||||
expectedDescriptors[0],
|
||||
ITagHelperDescriptorBuilder.Create("TestType2", "TestAssembly")
|
||||
.TagMatchingRule(rule => rule.RequireTagName("thstrong"))
|
||||
.Build()
|
||||
};
|
||||
var documentContext = TagHelperDocumentContext.Create("th", documentDescriptors);
|
||||
var service = new DefaultTagHelperFactsService();
|
||||
|
||||
// Act
|
||||
var descriptors = service.GetTagHelpersGivenTag(documentContext, "thstrong", "div");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedDescriptors, descriptors, TagHelperDescriptorComparer.CaseSensitive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTagHelpersGivenTag_RestrictsTagHelpersBasedOnParent()
|
||||
{
|
||||
// Arrange
|
||||
var expectedDescriptors = new[]
|
||||
{
|
||||
ITagHelperDescriptorBuilder.Create("TestType", "TestAssembly")
|
||||
.TagMatchingRule(
|
||||
rule => rule
|
||||
.RequireTagName("strong")
|
||||
.RequireParentTag("div"))
|
||||
.Build()
|
||||
};
|
||||
var documentDescriptors = new[]
|
||||
{
|
||||
expectedDescriptors[0],
|
||||
ITagHelperDescriptorBuilder.Create("TestType2", "TestAssembly")
|
||||
.TagMatchingRule(
|
||||
rule => rule
|
||||
.RequireTagName("strong")
|
||||
.RequireParentTag("p"))
|
||||
.Build()
|
||||
};
|
||||
var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors);
|
||||
var service = new DefaultTagHelperFactsService();
|
||||
|
||||
// Act
|
||||
var descriptors = service.GetTagHelpersGivenTag(documentContext, "strong", "div");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedDescriptors, descriptors, TagHelperDescriptorComparer.CaseSensitive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTagHelpersGivenParent_AllowsUnspecifiedParentTagHelpers()
|
||||
{
|
||||
// Arrange
|
||||
var documentDescriptors = new[]
|
||||
{
|
||||
ITagHelperDescriptorBuilder.Create("TestType", "TestAssembly")
|
||||
.TagMatchingRule(rule => rule.RequireTagName("div"))
|
||||
.Build()
|
||||
};
|
||||
var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors);
|
||||
var service = new DefaultTagHelperFactsService();
|
||||
|
||||
// Act
|
||||
var descriptors = service.GetTagHelpersGivenParent(documentContext, "p");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(documentDescriptors, descriptors, TagHelperDescriptorComparer.CaseSensitive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTagHelpersGivenParent_RestrictsTagHelpersBasedOnParent()
|
||||
{
|
||||
// Arrange
|
||||
var expectedDescriptors = new[]
|
||||
{
|
||||
ITagHelperDescriptorBuilder.Create("TestType", "TestAssembly")
|
||||
.TagMatchingRule(
|
||||
rule => rule
|
||||
.RequireTagName("p")
|
||||
.RequireParentTag("div"))
|
||||
.Build()
|
||||
};
|
||||
var documentDescriptors = new[]
|
||||
{
|
||||
expectedDescriptors[0],
|
||||
ITagHelperDescriptorBuilder.Create("TestType2", "TestAssembly")
|
||||
.TagMatchingRule(
|
||||
rule => rule
|
||||
.RequireTagName("strong")
|
||||
.RequireParentTag("p"))
|
||||
.Build()
|
||||
};
|
||||
var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors);
|
||||
var service = new DefaultTagHelperFactsService();
|
||||
|
||||
// Act
|
||||
var descriptors = service.GetTagHelpersGivenParent(documentContext, "div");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedDescriptors, descriptors, TagHelperDescriptorComparer.CaseSensitive);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue