Add ability to resolve all TagHelperDescriptors with one method call.
- Modified the AddOrRemoveTagHelperSpanVisitor to no longer manage TagHelperDescriptors found in the system. Instead it now manages TagHelperDirectiveDescriptors which are then used to resolve TagHelperDescriptors. - Changed the signature of ITagHelperDescriptorResolver to take in a TagHelperResolutionContext which will allow us to pass more information without breaking tooling. - TagHelperDescriptorResolver now resolves all TagHelperDescriptors at once and manages descriptors found in the system based on values on the provided TagHelperDirectiveDescriptors. #214
This commit is contained in:
parent
64a5b8ee22
commit
c35d19142c
|
|
@ -30,37 +30,30 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IEnumerable<TagHelperDescriptor> Resolve(string lookupText)
|
public IEnumerable<TagHelperDescriptor> Resolve([NotNull] TagHelperDescriptorResolutionContext context)
|
||||||
{
|
{
|
||||||
var lookupStrings = lookupText?.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
var resolvedDescriptors = new HashSet<TagHelperDescriptor>(TagHelperDescriptorComparer.Default);
|
||||||
|
|
||||||
// Ensure that we have valid lookupStrings to work with. Valid formats are:
|
foreach (var directiveDescriptor in context.DirectiveDescriptors)
|
||||||
// "assemblyName"
|
|
||||||
// "typeName, assemblyName"
|
|
||||||
if (string.IsNullOrEmpty(lookupText) ||
|
|
||||||
(lookupStrings.Length != 1 && lookupStrings.Length != 2))
|
|
||||||
{
|
{
|
||||||
throw new ArgumentException(
|
var lookupInfo = GetLookupInfo(directiveDescriptor);
|
||||||
Resources.FormatTagHelperDescriptorResolver_InvalidTagHelperLookupText(lookupText),
|
|
||||||
nameof(lookupText));
|
if (directiveDescriptor.DirectiveType == TagHelperDirectiveType.RemoveTagHelper)
|
||||||
|
{
|
||||||
|
resolvedDescriptors.RemoveWhere(descriptor => MatchesLookupInfo(descriptor, lookupInfo));
|
||||||
|
}
|
||||||
|
else if (directiveDescriptor.DirectiveType == TagHelperDirectiveType.AddTagHelper)
|
||||||
|
{
|
||||||
|
var descriptors = ResolveDescriptorsInAssembly(lookupInfo.AssemblyName);
|
||||||
|
|
||||||
|
// Only use descriptors that match our lookup info
|
||||||
|
descriptors = descriptors.Where(descriptor => MatchesLookupInfo(descriptor, lookupInfo));
|
||||||
|
|
||||||
|
resolvedDescriptors.UnionWith(descriptors);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab the assembly name from the lookup text strings. Due to our supported lookupText formats it will
|
return resolvedDescriptors;
|
||||||
// always be the last element provided.
|
|
||||||
var assemblyName = lookupStrings.Last().Trim();
|
|
||||||
var descriptors = ResolveDescriptorsInAssembly(assemblyName);
|
|
||||||
|
|
||||||
// Check if the lookupText specifies a type to search for.
|
|
||||||
if (lookupStrings.Length == 2)
|
|
||||||
{
|
|
||||||
// The user provided a type name. Retrieve it so we can prune our descriptors.
|
|
||||||
var typeName = lookupStrings[0].Trim();
|
|
||||||
|
|
||||||
descriptors = descriptors.Where(descriptor =>
|
|
||||||
string.Equals(descriptor.TypeName, typeName, StringComparison.Ordinal));
|
|
||||||
}
|
|
||||||
|
|
||||||
return descriptors;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -83,5 +76,59 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
|
|
||||||
return descriptors;
|
return descriptors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool MatchesLookupInfo(TagHelperDescriptor descriptor, LookupInfo lookupInfo)
|
||||||
|
{
|
||||||
|
if (!string.Equals(descriptor.AssemblyName, lookupInfo.AssemblyName, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.IsNullOrEmpty(lookupInfo.TypeName) ||
|
||||||
|
string.Equals(descriptor.TypeName, lookupInfo.TypeName, StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LookupInfo GetLookupInfo(TagHelperDirectiveDescriptor directiveDescriptor)
|
||||||
|
{
|
||||||
|
var lookupText = directiveDescriptor.LookupText;
|
||||||
|
var lookupStrings = lookupText?.Split(new[] { ',' });
|
||||||
|
|
||||||
|
// Ensure that we have valid lookupStrings to work with. Valid formats are:
|
||||||
|
// "assemblyName"
|
||||||
|
// "typeName, assemblyName"
|
||||||
|
if (lookupStrings == null ||
|
||||||
|
lookupStrings.Any(string.IsNullOrWhiteSpace) ||
|
||||||
|
(lookupStrings.Length != 1 && lookupStrings.Length != 2))
|
||||||
|
{
|
||||||
|
throw new ArgumentException(
|
||||||
|
Resources.FormatTagHelperDescriptorResolver_InvalidTagHelperLookupText(lookupText),
|
||||||
|
nameof(lookupText));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the assembly name from the lookup text strings. Due to our supported lookupText formats it will
|
||||||
|
// always be the last element provided.
|
||||||
|
var assemblyName = lookupStrings.Last().Trim();
|
||||||
|
string typeName = null;
|
||||||
|
|
||||||
|
// Check if the lookupText specifies a type to search for.
|
||||||
|
if (lookupStrings.Length == 2)
|
||||||
|
{
|
||||||
|
// The user provided a type name. Retrieve it so we can prune our descriptors.
|
||||||
|
typeName = lookupStrings[0].Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LookupInfo
|
||||||
|
{
|
||||||
|
AssemblyName = assemblyName,
|
||||||
|
TypeName = typeName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LookupInfo
|
||||||
|
{
|
||||||
|
public string AssemblyName { get; set; }
|
||||||
|
|
||||||
|
public string TypeName { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -18,21 +18,24 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
|
||||||
{
|
{
|
||||||
private readonly ITagHelperDescriptorResolver _descriptorResolver;
|
private readonly ITagHelperDescriptorResolver _descriptorResolver;
|
||||||
|
|
||||||
private List<TagHelperDescriptor> _descriptors;
|
private List<TagHelperDirectiveDescriptor> _directiveDescriptors;
|
||||||
|
|
||||||
public AddOrRemoveTagHelperSpanVisitor(ITagHelperDescriptorResolver descriptorResolver)
|
public AddOrRemoveTagHelperSpanVisitor([NotNull] ITagHelperDescriptorResolver descriptorResolver)
|
||||||
{
|
{
|
||||||
_descriptorResolver = descriptorResolver;
|
_descriptorResolver = descriptorResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<TagHelperDescriptor> GetDescriptors([NotNull] Block root)
|
public IEnumerable<TagHelperDescriptor> GetDescriptors([NotNull] Block root)
|
||||||
{
|
{
|
||||||
_descriptors = new List<TagHelperDescriptor>();
|
_directiveDescriptors = new List<TagHelperDirectiveDescriptor>();
|
||||||
|
|
||||||
// This will recurse through the syntax tree.
|
// This will recurse through the syntax tree.
|
||||||
VisitBlock(root);
|
VisitBlock(root);
|
||||||
|
|
||||||
return _descriptors;
|
var resolutionContext = new TagHelperDescriptorResolutionContext(_directiveDescriptors);
|
||||||
|
var descriptors = _descriptorResolver.Resolve(resolutionContext);
|
||||||
|
|
||||||
|
return descriptors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void VisitSpan(Span span)
|
public override void VisitSpan(Span span)
|
||||||
|
|
@ -43,34 +46,13 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
|
||||||
{
|
{
|
||||||
var codeGenerator = (AddOrRemoveTagHelperCodeGenerator)span.CodeGenerator;
|
var codeGenerator = (AddOrRemoveTagHelperCodeGenerator)span.CodeGenerator;
|
||||||
|
|
||||||
if (_descriptorResolver == null)
|
var directive = codeGenerator.RemoveTagHelperDescriptors ?
|
||||||
{
|
TagHelperDirectiveType.RemoveTagHelper :
|
||||||
var directive = codeGenerator.RemoveTagHelperDescriptors ?
|
TagHelperDirectiveType.AddTagHelper;
|
||||||
SyntaxConstants.CSharp.RemoveTagHelperKeyword :
|
|
||||||
SyntaxConstants.CSharp.AddTagHelperKeyword;
|
|
||||||
|
|
||||||
throw new InvalidOperationException(
|
var directiveDescriptor = new TagHelperDirectiveDescriptor(codeGenerator.LookupText, directive);
|
||||||
RazorResources.FormatTagHelpers_CannotUseDirectiveWithNoTagHelperDescriptorResolver(
|
|
||||||
directive, typeof(ITagHelperDescriptorResolver).FullName, typeof(RazorParser).FullName));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look up all the descriptors associated with the "LookupText".
|
_directiveDescriptors.Add(directiveDescriptor);
|
||||||
var descriptors = _descriptorResolver.Resolve(codeGenerator.LookupText);
|
|
||||||
|
|
||||||
if (codeGenerator.RemoveTagHelperDescriptors)
|
|
||||||
{
|
|
||||||
var evaluatedDescriptors =
|
|
||||||
new HashSet<TagHelperDescriptor>(descriptors, TagHelperDescriptorComparer.Default);
|
|
||||||
|
|
||||||
// We remove all found descriptors from the descriptor list to ignore the associated TagHelpers on the
|
|
||||||
// Razor page.
|
|
||||||
_descriptors.RemoveAll(descriptor => evaluatedDescriptors.Contains(descriptor));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Add all the found descriptors to our list.
|
|
||||||
_descriptors.AddRange(descriptors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1526,22 +1526,6 @@ namespace Microsoft.AspNet.Razor
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("ParseError_DirectiveMustBeSurroundedByQuotes"), p0);
|
return string.Format(CultureInfo.CurrentCulture, GetString("ParseError_DirectiveMustBeSurroundedByQuotes"), p0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Cannot use directive '{0}' when a {1} has not been provided to the {2}.
|
|
||||||
/// </summary>
|
|
||||||
internal static string TagHelpers_CannotUseDirectiveWithNoTagHelperDescriptorResolver
|
|
||||||
{
|
|
||||||
get { return GetString("TagHelpers_CannotUseDirectiveWithNoTagHelperDescriptorResolver"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Cannot use directive '{0}' when a {1} has not been provided to the {2}.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatTagHelpers_CannotUseDirectiveWithNoTagHelperDescriptorResolver(object p0, object p1, object p2)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelpers_CannotUseDirectiveWithNoTagHelperDescriptorResolver"), p0, p1, p2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Found a malformed '{0}' tag helper. Tag helpers must have a start and end tag or be self closing.
|
/// Found a malformed '{0}' tag helper. Tag helpers must have a start and end tag or be self closing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -421,9 +421,6 @@ Instead, wrap the contents of the block in "{{}}":
|
||||||
<data name="ParseError_DirectiveMustBeSurroundedByQuotes" xml:space="preserve">
|
<data name="ParseError_DirectiveMustBeSurroundedByQuotes" xml:space="preserve">
|
||||||
<value>Directive '{0}'s value must be surrounded in double quotes.</value>
|
<value>Directive '{0}'s value must be surrounded in double quotes.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TagHelpers_CannotUseDirectiveWithNoTagHelperDescriptorResolver" xml:space="preserve">
|
|
||||||
<value>Cannot use directive '{0}' when a {1} has not been provided to the {2}.</value>
|
|
||||||
</data>
|
|
||||||
<data name="TagHelpersParseTreeRewriter_FoundMalformedTagHelper" xml:space="preserve">
|
<data name="TagHelpersParseTreeRewriter_FoundMalformedTagHelper" xml:space="preserve">
|
||||||
<value>Found a malformed '{0}' tag helper. Tag helpers must have a start and end tag or be self closing.</value>
|
<value>Found a malformed '{0}' tag helper. Tag helpers must have a start and end tag or be self closing.</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,13 @@ namespace Microsoft.AspNet.Razor.TagHelpers
|
||||||
public interface ITagHelperDescriptorResolver
|
public interface ITagHelperDescriptorResolver
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resolves <see cref="TagHelperDescriptor"/>s matching the given <paramref name="lookupText"/>.
|
/// Resolves <see cref="TagHelperDescriptor"/>s based on the given <paramref name="resolutionContext"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="lookupText">
|
/// <param name="resolutionContext">
|
||||||
/// A <see cref="string"/> used to find tag helper <see cref="Type"/>s.
|
/// <see cref="TagHelperDescriptorResolutionContext"/> used to resolve descriptors for the Razor page.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <returns>An <see cref="IEnumerable{TagHelperDescriptor}"/> of <see cref="TagHelperDescriptor"/>s matching
|
/// <returns>An <see cref="IEnumerable{TagHelperDescriptor}"/> of <see cref="TagHelperDescriptor"/>s based
|
||||||
/// the given <paramref name="lookupText"/>.</returns>
|
/// on the given <paramref name="resolutionContext"/>.</returns>
|
||||||
IEnumerable<TagHelperDescriptor> Resolve(string lookupText);
|
IEnumerable<TagHelperDescriptor> Resolve(TagHelperDescriptorResolutionContext resolutionContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. 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;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Razor.TagHelpers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains information needed to resolve <see cref="TagHelperDescriptor"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public class TagHelperDescriptorResolutionContext
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Instantiates a new instance of <see cref="TagHelperDescriptorResolutionContext"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="directiveDescriptors"><see cref="TagHelperDirectiveDescriptor"/>s used to resolve
|
||||||
|
/// <see cref="TagHelperDescriptor"/>s.</param>
|
||||||
|
public TagHelperDescriptorResolutionContext(
|
||||||
|
[NotNull] IEnumerable<TagHelperDirectiveDescriptor> directiveDescriptors)
|
||||||
|
{
|
||||||
|
DirectiveDescriptors = new List<TagHelperDirectiveDescriptor>(directiveDescriptors);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="TagHelperDirectiveDescriptor"/>s used to resolve <see cref="TagHelperDescriptor"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public IList<TagHelperDirectiveDescriptor> DirectiveDescriptors { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Razor.TagHelpers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains information needed to resolve <see cref="TagHelperDescriptor"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public class TagHelperDirectiveDescriptor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Instantiates a new instance of <see cref="TagHelperDirectiveDescriptor"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lookupText">A <see cref="string"/> used to find tag helper <see cref="System.Type"/>s.</param>
|
||||||
|
/// <param name="directiveType">The <see cref="TagHelperDirectiveType"/> of this directive.</param>
|
||||||
|
public TagHelperDirectiveDescriptor([NotNull] string lookupText, TagHelperDirectiveType directiveType)
|
||||||
|
{
|
||||||
|
LookupText = lookupText;
|
||||||
|
DirectiveType = directiveType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="string"/> used to find tag helper <see cref="System.Type"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public string LookupText { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="TagHelperDirectiveType"/> of this directive.
|
||||||
|
/// </summary>
|
||||||
|
public TagHelperDirectiveType DirectiveType { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Razor.TagHelpers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of tag helper directive.
|
||||||
|
/// </summary>
|
||||||
|
public enum TagHelperDirectiveType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An @addtaghelper directive.
|
||||||
|
/// </summary>
|
||||||
|
AddTagHelper,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A @removetaghelper directive.
|
||||||
|
/// </summary>
|
||||||
|
RemoveTagHelper
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue