Fix: Nested tag helpers do not work when tag helper prefix is set
This commit is contained in:
parent
db805eb3e3
commit
45732a5dd3
|
|
@ -44,7 +44,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
||||||
private readonly Stack<BlockBuilder> _blockStack;
|
private readonly Stack<BlockBuilder> _blockStack;
|
||||||
private TagHelperBlockTracker _currentTagHelperTracker;
|
private TagHelperBlockTracker _currentTagHelperTracker;
|
||||||
private BlockBuilder _currentBlock;
|
private BlockBuilder _currentBlock;
|
||||||
private string _currentParentTagName;
|
|
||||||
|
|
||||||
public TagHelperParseTreeRewriter(string tagHelperPrefix, IEnumerable<TagHelperDescriptor> descriptors)
|
public TagHelperParseTreeRewriter(string tagHelperPrefix, IEnumerable<TagHelperDescriptor> descriptors)
|
||||||
{
|
{
|
||||||
|
|
@ -56,6 +55,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
||||||
_htmlAttributeTracker = new List<KeyValuePair<string, string>>();
|
_htmlAttributeTracker = new List<KeyValuePair<string, string>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TagBlockTracker CurrentTracker => _trackerStack.Count > 0 ? _trackerStack.Peek() : null;
|
||||||
|
|
||||||
|
private string CurrentParentTagName => CurrentTracker?.TagName;
|
||||||
|
|
||||||
|
private bool CurrentParentIsTagHelper => CurrentTracker?.IsTagHelper ?? false;
|
||||||
|
|
||||||
public Block Rewrite(Block syntaxTree, ErrorSink errorSink)
|
public Block Rewrite(Block syntaxTree, ErrorSink errorSink)
|
||||||
{
|
{
|
||||||
RewriteTags(syntaxTree, errorSink, depth: 0);
|
RewriteTags(syntaxTree, errorSink, depth: 0);
|
||||||
|
|
@ -189,7 +194,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
||||||
// We're now in a start tag block, we first need to see if the tag block is a tag helper.
|
// We're now in a start tag block, we first need to see if the tag block is a tag helper.
|
||||||
var elementAttributes = GetAttributeNameValuePairs(tagBlock);
|
var elementAttributes = GetAttributeNameValuePairs(tagBlock);
|
||||||
|
|
||||||
tagHelperBinding = _tagHelperBinder.GetBinding(tagName, elementAttributes, _currentParentTagName);
|
tagHelperBinding = _tagHelperBinder.GetBinding(
|
||||||
|
tagName,
|
||||||
|
elementAttributes,
|
||||||
|
CurrentParentTagName,
|
||||||
|
CurrentParentIsTagHelper);
|
||||||
|
|
||||||
// If there aren't any TagHelperDescriptors registered then we aren't a TagHelper
|
// If there aren't any TagHelperDescriptors registered then we aren't a TagHelper
|
||||||
if (tagHelperBinding == null)
|
if (tagHelperBinding == null)
|
||||||
|
|
@ -257,7 +266,8 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
||||||
tagHelperBinding = _tagHelperBinder.GetBinding(
|
tagHelperBinding = _tagHelperBinder.GetBinding(
|
||||||
tagName,
|
tagName,
|
||||||
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
||||||
parentTagName: _currentParentTagName);
|
parentTagName: CurrentParentTagName,
|
||||||
|
parentIsTagHelper: CurrentParentIsTagHelper);
|
||||||
|
|
||||||
// If there are not TagHelperDescriptors associated with the end tag block that also have no
|
// If there are not TagHelperDescriptors associated with the end tag block that also have no
|
||||||
// required attributes then it means we can't be a TagHelper, bail out.
|
// required attributes then it means we can't be a TagHelper, bail out.
|
||||||
|
|
@ -508,10 +518,20 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentTracker = _trackerStack.Count > 0 ? _trackerStack.Peek() : null;
|
if (!HasAllowedChildren())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (HasAllowedChildren() &&
|
var tagHelperBinding = _tagHelperBinder.GetBinding(
|
||||||
!_currentTagHelperTracker.AllowedChildren.Contains(tagName, StringComparer.OrdinalIgnoreCase))
|
tagName,
|
||||||
|
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
||||||
|
parentTagName: CurrentParentTagName,
|
||||||
|
parentIsTagHelper: CurrentParentIsTagHelper);
|
||||||
|
|
||||||
|
// If we found a binding for the current tag, then it is a tag helper. Use the prefixed allowed children to compare.
|
||||||
|
var allowedChildren = tagHelperBinding != null ? _currentTagHelperTracker.PrefixedAllowedChildren : _currentTagHelperTracker.AllowedChildren;
|
||||||
|
if (!allowedChildren.Contains(tagName, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
OnAllowedChildrenTagError(_currentTagHelperTracker, tagName, tagBlock, errorSink);
|
OnAllowedChildrenTagError(_currentTagHelperTracker, tagName, tagBlock, errorSink);
|
||||||
}
|
}
|
||||||
|
|
@ -812,14 +832,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
||||||
|
|
||||||
private void PushTrackerStack(TagBlockTracker tracker)
|
private void PushTrackerStack(TagBlockTracker tracker)
|
||||||
{
|
{
|
||||||
_currentParentTagName = tracker.TagName;
|
|
||||||
_trackerStack.Push(tracker);
|
_trackerStack.Push(tracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TagBlockTracker PopTrackerStack()
|
private TagBlockTracker PopTrackerStack()
|
||||||
{
|
{
|
||||||
var poppedTracker = _trackerStack.Pop();
|
var poppedTracker = _trackerStack.Pop();
|
||||||
_currentParentTagName = _trackerStack.Count > 0 ? _trackerStack.Peek().TagName : null;
|
|
||||||
|
|
||||||
return poppedTracker;
|
return poppedTracker;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,12 +39,14 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
/// retrieves catch-all <see cref="TagHelperDescriptor"/>s (descriptors that target every tag).</param>
|
/// retrieves catch-all <see cref="TagHelperDescriptor"/>s (descriptors that target every tag).</param>
|
||||||
/// <param name="attributes">Attributes on the HTML tag.</param>
|
/// <param name="attributes">Attributes on the HTML tag.</param>
|
||||||
/// <param name="parentTagName">The parent tag name of the given <paramref name="tagName"/> tag.</param>
|
/// <param name="parentTagName">The parent tag name of the given <paramref name="tagName"/> tag.</param>
|
||||||
|
/// <param name="parentIsTagHelper">Is the parent tag of the given <paramref name="tagName"/> tag a tag helper.</param>
|
||||||
/// <returns><see cref="TagHelperDescriptor"/>s that apply to the given HTML tag criteria.
|
/// <returns><see cref="TagHelperDescriptor"/>s that apply to the given HTML tag criteria.
|
||||||
/// Will return <c>null</c> if no <see cref="TagHelperDescriptor"/>s are a match.</returns>
|
/// Will return <c>null</c> if no <see cref="TagHelperDescriptor"/>s are a match.</returns>
|
||||||
public TagHelperBinding GetBinding(
|
public TagHelperBinding GetBinding(
|
||||||
string tagName,
|
string tagName,
|
||||||
IReadOnlyList<KeyValuePair<string, string>> attributes,
|
IReadOnlyList<KeyValuePair<string, string>> attributes,
|
||||||
string parentTagName)
|
string parentTagName,
|
||||||
|
bool parentIsTagHelper)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(_tagHelperPrefix) &&
|
if (!string.IsNullOrEmpty(_tagHelperPrefix) &&
|
||||||
(tagName.Length <= _tagHelperPrefix.Length ||
|
(tagName.Length <= _tagHelperPrefix.Length ||
|
||||||
|
|
@ -74,11 +76,17 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
}
|
}
|
||||||
|
|
||||||
var tagNameWithoutPrefix = _tagHelperPrefix != null ? tagName.Substring(_tagHelperPrefix.Length) : tagName;
|
var tagNameWithoutPrefix = _tagHelperPrefix != null ? tagName.Substring(_tagHelperPrefix.Length) : tagName;
|
||||||
|
var parentTagNameWithoutPrefix = parentTagName;
|
||||||
|
if (_tagHelperPrefix != null && parentIsTagHelper)
|
||||||
|
{
|
||||||
|
parentTagNameWithoutPrefix = parentTagName.Substring(_tagHelperPrefix.Length);
|
||||||
|
}
|
||||||
|
|
||||||
Dictionary<TagHelperDescriptor, IReadOnlyList<TagMatchingRuleDescriptor>> applicableDescriptorMappings = null;
|
Dictionary<TagHelperDescriptor, IReadOnlyList<TagMatchingRuleDescriptor>> applicableDescriptorMappings = null;
|
||||||
foreach (var descriptor in descriptors)
|
foreach (var descriptor in descriptors)
|
||||||
{
|
{
|
||||||
var applicableRules = descriptor.TagMatchingRules.Where(
|
var applicableRules = descriptor.TagMatchingRules.Where(
|
||||||
rule => TagHelperMatchingConventions.SatisfiesRule(tagNameWithoutPrefix, parentTagName, attributes, rule));
|
rule => TagHelperMatchingConventions.SatisfiesRule(tagNameWithoutPrefix, parentTagNameWithoutPrefix, attributes, rule));
|
||||||
|
|
||||||
if (applicableRules.Any())
|
if (applicableRules.Any())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
|
|
||||||
public static bool SatisfiesRule(
|
public static bool SatisfiesRule(
|
||||||
string tagNameWithoutPrefix,
|
string tagNameWithoutPrefix,
|
||||||
string parentTagName,
|
string parentTagNameWithoutPrefix,
|
||||||
IEnumerable<KeyValuePair<string, string>> tagAttributes,
|
IEnumerable<KeyValuePair<string, string>> tagAttributes,
|
||||||
TagMatchingRuleDescriptor rule)
|
TagMatchingRuleDescriptor rule)
|
||||||
{
|
{
|
||||||
|
|
@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var satisfiesParentTag = SatisfiesParentTag(parentTagName, rule);
|
var satisfiesParentTag = SatisfiesParentTag(parentTagNameWithoutPrefix, rule);
|
||||||
if (!satisfiesParentTag)
|
if (!satisfiesParentTag)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -89,14 +89,14 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool SatisfiesParentTag(string parentTagName, TagMatchingRuleDescriptor rule)
|
public static bool SatisfiesParentTag(string parentTagNameWithoutPrefix, TagMatchingRuleDescriptor rule)
|
||||||
{
|
{
|
||||||
if (rule == null)
|
if (rule == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(rule));
|
throw new ArgumentNullException(nameof(rule));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rule.ParentTag != null && !string.Equals(parentTagName, rule.ParentTag, StringComparison.OrdinalIgnoreCase))
|
if (rule.ParentTag != null && !string.Equals(parentTagNameWithoutPrefix, rule.ParentTag, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,13 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
var prefix = documentContext.Prefix ?? string.Empty;
|
var prefix = documentContext.Prefix ?? string.Empty;
|
||||||
Debug.Assert(completionContext.CurrentTagName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase));
|
Debug.Assert(completionContext.CurrentTagName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
var applicableTagHelperBinding = _tagHelperFactsService.GetTagHelperBinding(documentContext, completionContext.CurrentTagName, completionContext.Attributes, completionContext.CurrentParentTagName);
|
var applicableTagHelperBinding = _tagHelperFactsService.GetTagHelperBinding(
|
||||||
|
documentContext,
|
||||||
|
completionContext.CurrentTagName,
|
||||||
|
completionContext.Attributes,
|
||||||
|
completionContext.CurrentParentTagName,
|
||||||
|
parentIsTagHelper: false);
|
||||||
|
|
||||||
var applicableDescriptors = applicableTagHelperBinding?.Descriptors ?? Enumerable.Empty<TagHelperDescriptor>();
|
var applicableDescriptors = applicableTagHelperBinding?.Descriptors ?? Enumerable.Empty<TagHelperDescriptor>();
|
||||||
var unprefixedTagName = completionContext.CurrentTagName.Substring(prefix.Length);
|
var unprefixedTagName = completionContext.CurrentTagName.Substring(prefix.Length);
|
||||||
|
|
||||||
|
|
@ -227,11 +233,13 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
}
|
}
|
||||||
|
|
||||||
var prefix = completionContext.DocumentContext.Prefix ?? string.Empty;
|
var prefix = completionContext.DocumentContext.Prefix ?? string.Empty;
|
||||||
|
|
||||||
var binding = _tagHelperFactsService.GetTagHelperBinding(
|
var binding = _tagHelperFactsService.GetTagHelperBinding(
|
||||||
completionContext.DocumentContext,
|
completionContext.DocumentContext,
|
||||||
completionContext.ContainingTagName,
|
completionContext.ContainingTagName,
|
||||||
completionContext.Attributes,
|
completionContext.Attributes,
|
||||||
completionContext.ContainingParentTagName);
|
completionContext.ContainingParentTagName,
|
||||||
|
completionContext.ContainingParentIsTagHelper);
|
||||||
|
|
||||||
if (binding == null)
|
if (binding == null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,8 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
TagHelperDocumentContext documentContext,
|
TagHelperDocumentContext documentContext,
|
||||||
string tagName,
|
string tagName,
|
||||||
IEnumerable<KeyValuePair<string, string>> attributes,
|
IEnumerable<KeyValuePair<string, string>> attributes,
|
||||||
string parentTag)
|
string parentTag,
|
||||||
|
bool parentIsTagHelper)
|
||||||
{
|
{
|
||||||
if (documentContext == null)
|
if (documentContext == null)
|
||||||
{
|
{
|
||||||
|
|
@ -39,7 +40,7 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
|
|
||||||
var prefix = documentContext.Prefix;
|
var prefix = documentContext.Prefix;
|
||||||
var tagHelperBinder = new TagHelperBinder(prefix, descriptors);
|
var tagHelperBinder = new TagHelperBinder(prefix, descriptors);
|
||||||
var binding = tagHelperBinder.GetBinding(tagName, attributes.ToList(), parentTag);
|
var binding = tagHelperBinder.GetBinding(tagName, attributes.ToList(), parentTag, parentIsTagHelper);
|
||||||
|
|
||||||
return binding;
|
return binding;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
string containingTagName,
|
string containingTagName,
|
||||||
IEnumerable<KeyValuePair<string, string>> attributes,
|
IEnumerable<KeyValuePair<string, string>> attributes,
|
||||||
string containingParentTagName,
|
string containingParentTagName,
|
||||||
|
bool containingParentIsTagHelper,
|
||||||
Func<string, bool> inHTMLSchema)
|
Func<string, bool> inHTMLSchema)
|
||||||
{
|
{
|
||||||
if (documentContext == null)
|
if (documentContext == null)
|
||||||
|
|
@ -37,6 +38,7 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
ContainingTagName = containingTagName;
|
ContainingTagName = containingTagName;
|
||||||
Attributes = attributes;
|
Attributes = attributes;
|
||||||
ContainingParentTagName = containingParentTagName;
|
ContainingParentTagName = containingParentTagName;
|
||||||
|
ContainingParentIsTagHelper = containingParentIsTagHelper;
|
||||||
InHTMLSchema = inHTMLSchema;
|
InHTMLSchema = inHTMLSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,6 +52,8 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
|
|
||||||
public string ContainingParentTagName { get; }
|
public string ContainingParentTagName { get; }
|
||||||
|
|
||||||
|
public bool ContainingParentIsTagHelper { get; }
|
||||||
|
|
||||||
public Func<string, bool> InHTMLSchema { get; }
|
public Func<string, bool> InHTMLSchema { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
{
|
{
|
||||||
public abstract class TagHelperFactsService : ILanguageService
|
public abstract class TagHelperFactsService : ILanguageService
|
||||||
{
|
{
|
||||||
public abstract TagHelperBinding GetTagHelperBinding(TagHelperDocumentContext documentContext, string tagName, IEnumerable<KeyValuePair<string, string>> attributes, string parentTag);
|
public abstract TagHelperBinding GetTagHelperBinding(TagHelperDocumentContext documentContext, string tagName, IEnumerable<KeyValuePair<string, string>> attributes, string parentTag, bool parentIsTagHelper);
|
||||||
|
|
||||||
public abstract IEnumerable<BoundAttributeDescriptor> GetBoundTagHelperAttributes(TagHelperDocumentContext documentContext, string attributeName, TagHelperBinding binding);
|
public abstract IEnumerable<BoundAttributeDescriptor> GetBoundTagHelperAttributes(TagHelperDocumentContext documentContext, string attributeName, TagHelperBinding binding);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,12 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
||||||
var prefix = documentContext.Prefix ?? string.Empty;
|
var prefix = documentContext.Prefix ?? string.Empty;
|
||||||
Debug.Assert(completionContext.CurrentTagName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase));
|
Debug.Assert(completionContext.CurrentTagName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
var applicableTagHelperBinding = _tagHelperFactsService.GetTagHelperBinding(documentContext, completionContext.CurrentTagName, completionContext.Attributes, completionContext.CurrentParentTagName);
|
var applicableTagHelperBinding = _tagHelperFactsService.GetTagHelperBinding(
|
||||||
|
documentContext,
|
||||||
|
completionContext.CurrentTagName,
|
||||||
|
completionContext.Attributes,
|
||||||
|
completionContext.CurrentParentTagName);
|
||||||
|
|
||||||
var applicableDescriptors = applicableTagHelperBinding?.Descriptors ?? Enumerable.Empty<TagHelperDescriptor>();
|
var applicableDescriptors = applicableTagHelperBinding?.Descriptors ?? Enumerable.Empty<TagHelperDescriptor>();
|
||||||
var unprefixedTagName = completionContext.CurrentTagName.Substring(prefix.Length);
|
var unprefixedTagName = completionContext.CurrentTagName.Substring(prefix.Length);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
||||||
|
|
||||||
var prefix = documentContext.Prefix;
|
var prefix = documentContext.Prefix;
|
||||||
var tagHelperBinder = new TagHelperBinder(prefix, descriptors);
|
var tagHelperBinder = new TagHelperBinder(prefix, descriptors);
|
||||||
var binding = tagHelperBinder.GetBinding(tagName, attributes.ToList(), parentTag);
|
var binding = tagHelperBinder.GetBinding(tagName, attributes.ToList(), parentTag, parentIsTagHelper: false);
|
||||||
|
|
||||||
return binding;
|
return binding;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -385,6 +385,99 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
|
||||||
tagHelperPrefix: "th:");
|
tagHelperPrefix: "th:");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Rewrite_UnderstandsTagHelperPrefixAndAllowedChildrenAndRequireParent()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var documentContent = "<th:p><th:strong></th:strong></th:p>";
|
||||||
|
var expectedOutput = new MarkupBlock(
|
||||||
|
new MarkupTagHelperBlock("th:p",
|
||||||
|
new MarkupTagHelperBlock("th:strong")));
|
||||||
|
var descriptors = new TagHelperDescriptor[]
|
||||||
|
{
|
||||||
|
TagHelperDescriptorBuilder.Create("PTagHelper", "SomeAssembly")
|
||||||
|
.TagMatchingRuleDescriptor(rule => rule.RequireTagName("p"))
|
||||||
|
.AllowChildTag("strong")
|
||||||
|
.Build(),
|
||||||
|
TagHelperDescriptorBuilder.Create("StrongTagHelper", "SomeAssembly")
|
||||||
|
.TagMatchingRuleDescriptor(rule => rule.RequireTagName("strong").RequireParentTag("p"))
|
||||||
|
.Build(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
EvaluateData(
|
||||||
|
descriptors,
|
||||||
|
documentContent,
|
||||||
|
expectedOutput,
|
||||||
|
expectedErrors: Enumerable.Empty<RazorError>(),
|
||||||
|
tagHelperPrefix: "th:");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Rewrite_InvalidStructure_UnderstandsTagHelperPrefixAndAllowedChildrenAndRequireParent()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var documentContent = "<th:p></th:strong></th:p>";
|
||||||
|
var expectedOutput = new MarkupBlock(
|
||||||
|
new MarkupTagHelperBlock("th:p",
|
||||||
|
new MarkupTagBlock(
|
||||||
|
Factory.Markup("</th:strong>"))));
|
||||||
|
var descriptors = new TagHelperDescriptor[]
|
||||||
|
{
|
||||||
|
TagHelperDescriptorBuilder.Create("PTagHelper", "SomeAssembly")
|
||||||
|
.TagMatchingRuleDescriptor(rule => rule.RequireTagName("p"))
|
||||||
|
.AllowChildTag("strong")
|
||||||
|
.Build(),
|
||||||
|
TagHelperDescriptorBuilder.Create("StrongTagHelper", "SomeAssembly")
|
||||||
|
.TagMatchingRuleDescriptor(rule => rule.RequireTagName("strong").RequireParentTag("p"))
|
||||||
|
.Build(),
|
||||||
|
};
|
||||||
|
var expectedErrors = new[] {
|
||||||
|
new RazorError(
|
||||||
|
LegacyResources.FormatTagHelpersParseTreeRewriter_FoundMalformedTagHelper("th:strong"),
|
||||||
|
absoluteIndex: 8,
|
||||||
|
lineIndex: 0,
|
||||||
|
columnIndex: 8,
|
||||||
|
length: 9),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
EvaluateData(
|
||||||
|
descriptors,
|
||||||
|
documentContent,
|
||||||
|
expectedOutput,
|
||||||
|
expectedErrors: expectedErrors,
|
||||||
|
tagHelperPrefix: "th:");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Rewrite_NonTagHelperChild_UnderstandsTagHelperPrefixAndAllowedChildren()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var documentContent = "<th:p><strong></strong></th:p>";
|
||||||
|
var expectedOutput = new MarkupBlock(
|
||||||
|
new MarkupTagHelperBlock("th:p",
|
||||||
|
new MarkupTagBlock(
|
||||||
|
Factory.Markup("<strong>")),
|
||||||
|
new MarkupTagBlock(
|
||||||
|
Factory.Markup("</strong>"))));
|
||||||
|
var descriptors = new TagHelperDescriptor[]
|
||||||
|
{
|
||||||
|
TagHelperDescriptorBuilder.Create("PTagHelper", "SomeAssembly")
|
||||||
|
.TagMatchingRuleDescriptor(rule => rule.RequireTagName("p"))
|
||||||
|
.AllowChildTag("strong")
|
||||||
|
.Build(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
EvaluateData(
|
||||||
|
descriptors,
|
||||||
|
documentContent,
|
||||||
|
expectedOutput,
|
||||||
|
expectedErrors: Enumerable.Empty<RazorError>(),
|
||||||
|
tagHelperPrefix: "th:");
|
||||||
|
}
|
||||||
|
|
||||||
public static TheoryData InvalidHtmlScriptBlockData
|
public static TheoryData InvalidHtmlScriptBlockData
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
var bindingResult = tagHelperBinder.GetBinding(
|
var bindingResult = tagHelperBinder.GetBinding(
|
||||||
tagName: "th:div",
|
tagName: "th:div",
|
||||||
attributes: expectedAttributes,
|
attributes: expectedAttributes,
|
||||||
parentTagName: "body");
|
parentTagName: "body",
|
||||||
|
parentIsTagHelper: false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedDescriptors, bindingResult.Descriptors, TagHelperDescriptorComparer.CaseSensitive);
|
Assert.Equal(expectedDescriptors, bindingResult.Descriptors, TagHelperDescriptorComparer.CaseSensitive);
|
||||||
|
|
@ -109,7 +110,8 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
var bindingResult = tagHelperBinder.GetBinding(
|
var bindingResult = tagHelperBinder.GetBinding(
|
||||||
tagName,
|
tagName,
|
||||||
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
||||||
parentTagName: parentTagName);
|
parentTagName: parentTagName,
|
||||||
|
parentIsTagHelper: false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal((IEnumerable<TagHelperDescriptor>)expectedDescriptors, bindingResult.Descriptors, TagHelperDescriptorComparer.CaseSensitive);
|
Assert.Equal((IEnumerable<TagHelperDescriptor>)expectedDescriptors, bindingResult.Descriptors, TagHelperDescriptorComparer.CaseSensitive);
|
||||||
|
|
@ -272,7 +274,7 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
var tagHelperBinder = new TagHelperBinder(null, (IReadOnlyList<TagHelperDescriptor>)availableDescriptors);
|
var tagHelperBinder = new TagHelperBinder(null, (IReadOnlyList<TagHelperDescriptor>)availableDescriptors);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var bindingResult = tagHelperBinder.GetBinding(tagName, providedAttributes, parentTagName: "p");
|
var bindingResult = tagHelperBinder.GetBinding(tagName, providedAttributes, parentTagName: "p", parentIsTagHelper: false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal((IEnumerable<TagHelperDescriptor>)expectedDescriptors, bindingResult?.Descriptors, TagHelperDescriptorComparer.CaseSensitive);
|
Assert.Equal((IEnumerable<TagHelperDescriptor>)expectedDescriptors, bindingResult?.Descriptors, TagHelperDescriptorComparer.CaseSensitive);
|
||||||
|
|
@ -292,7 +294,8 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
var bindingResult = tagHelperBinder.GetBinding(
|
var bindingResult = tagHelperBinder.GetBinding(
|
||||||
tagName: "th",
|
tagName: "th",
|
||||||
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
||||||
parentTagName: "p");
|
parentTagName: "p",
|
||||||
|
parentIsTagHelper: false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Null(bindingResult);
|
Assert.Null(bindingResult);
|
||||||
|
|
@ -312,11 +315,13 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
var bindingResultDiv = tagHelperBinder.GetBinding(
|
var bindingResultDiv = tagHelperBinder.GetBinding(
|
||||||
tagName: "th:div",
|
tagName: "th:div",
|
||||||
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
||||||
parentTagName: "p");
|
parentTagName: "p",
|
||||||
|
parentIsTagHelper: false);
|
||||||
var bindingResultSpan = tagHelperBinder.GetBinding(
|
var bindingResultSpan = tagHelperBinder.GetBinding(
|
||||||
tagName: "th:span",
|
tagName: "th:span",
|
||||||
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
||||||
parentTagName: "p");
|
parentTagName: "p",
|
||||||
|
parentIsTagHelper: false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var descriptor = Assert.Single(bindingResultDiv.Descriptors);
|
var descriptor = Assert.Single(bindingResultDiv.Descriptors);
|
||||||
|
|
@ -339,7 +344,8 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
var bindingResult = tagHelperBinder.GetBinding(
|
var bindingResult = tagHelperBinder.GetBinding(
|
||||||
tagName: "th:div",
|
tagName: "th:div",
|
||||||
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
||||||
parentTagName: "p");
|
parentTagName: "p",
|
||||||
|
parentIsTagHelper: false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var descriptor = Assert.Single(bindingResult.Descriptors);
|
var descriptor = Assert.Single(bindingResult.Descriptors);
|
||||||
|
|
@ -362,7 +368,8 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
var bindingResult = tagHelperBinder.GetBinding(
|
var bindingResult = tagHelperBinder.GetBinding(
|
||||||
tagName: "div",
|
tagName: "div",
|
||||||
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
||||||
parentTagName: "p");
|
parentTagName: "p",
|
||||||
|
parentIsTagHelper: false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Null(bindingResult);
|
Assert.Null(bindingResult);
|
||||||
|
|
@ -385,7 +392,8 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
var tagHelperBinding = tagHelperBinder.GetBinding(
|
var tagHelperBinding = tagHelperBinder.GetBinding(
|
||||||
tagName: "foo",
|
tagName: "foo",
|
||||||
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
||||||
parentTagName: "p");
|
parentTagName: "p",
|
||||||
|
parentIsTagHelper: false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Null(tagHelperBinding);
|
Assert.Null(tagHelperBinding);
|
||||||
|
|
@ -411,11 +419,13 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
var divBinding = tagHelperBinder.GetBinding(
|
var divBinding = tagHelperBinder.GetBinding(
|
||||||
tagName: "div",
|
tagName: "div",
|
||||||
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
||||||
parentTagName: "p");
|
parentTagName: "p",
|
||||||
|
parentIsTagHelper: false);
|
||||||
var spanBinding = tagHelperBinder.GetBinding(
|
var spanBinding = tagHelperBinder.GetBinding(
|
||||||
tagName: "span",
|
tagName: "span",
|
||||||
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
||||||
parentTagName: "p");
|
parentTagName: "p",
|
||||||
|
parentIsTagHelper: false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
// For divs
|
// For divs
|
||||||
|
|
@ -443,7 +453,8 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
var bindingResult = tagHelperBinder.GetBinding(
|
var bindingResult = tagHelperBinder.GetBinding(
|
||||||
tagName: "div",
|
tagName: "div",
|
||||||
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
||||||
parentTagName: "p");
|
parentTagName: "p",
|
||||||
|
parentIsTagHelper: false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var descriptor = Assert.Single(bindingResult.Descriptors);
|
var descriptor = Assert.Single(bindingResult.Descriptors);
|
||||||
|
|
@ -470,7 +481,8 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
var binding = tagHelperBinder.GetBinding(
|
var binding = tagHelperBinder.GetBinding(
|
||||||
tagName: "div",
|
tagName: "div",
|
||||||
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
||||||
parentTagName: "p");
|
parentTagName: "p",
|
||||||
|
parentIsTagHelper: false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var boundDescriptor = Assert.Single(binding.Descriptors);
|
var boundDescriptor = Assert.Single(binding.Descriptors);
|
||||||
|
|
@ -479,5 +491,34 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
var boundRule = Assert.Single(boundRules);
|
var boundRule = Assert.Single(boundRules);
|
||||||
Assert.Equal("div", boundRule.TagName);
|
Assert.Equal("div", boundRule.TagName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetBinding_PrefixedParent_ReturnsBinding()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var divDescriptor = TagHelperDescriptorBuilder.Create("foo1", "SomeAssembly")
|
||||||
|
.TagMatchingRuleDescriptor(rule => rule.RequireTagName("div").RequireParentTag("p"))
|
||||||
|
.Build();
|
||||||
|
var pDescriptor = TagHelperDescriptorBuilder.Create("foo2", "SomeAssembly")
|
||||||
|
.TagMatchingRuleDescriptor(rule => rule.RequireTagName("p"))
|
||||||
|
.Build();
|
||||||
|
var descriptors = new[] { divDescriptor, pDescriptor };
|
||||||
|
var tagHelperBinder = new TagHelperBinder("th:", descriptors);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var bindingResult = tagHelperBinder.GetBinding(
|
||||||
|
tagName: "th:div",
|
||||||
|
attributes: Array.Empty<KeyValuePair<string, string>>(),
|
||||||
|
parentTagName: "th:p",
|
||||||
|
parentIsTagHelper: true);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var boundDescriptor = Assert.Single(bindingResult.Descriptors);
|
||||||
|
Assert.Same(divDescriptor, boundDescriptor);
|
||||||
|
var boundRules = bindingResult.GetBoundRules(boundDescriptor);
|
||||||
|
var boundRule = Assert.Single(boundRules);
|
||||||
|
Assert.Equal("div", boundRule.TagName);
|
||||||
|
Assert.Equal("p", boundRule.ParentTag);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -927,6 +927,7 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
IEnumerable<string> existingCompletions,
|
IEnumerable<string> existingCompletions,
|
||||||
string containingTagName,
|
string containingTagName,
|
||||||
string containingParentTagName = "body",
|
string containingParentTagName = "body",
|
||||||
|
bool containingParentIsTagHelper = false,
|
||||||
string tagHelperPrefix = "")
|
string tagHelperPrefix = "")
|
||||||
{
|
{
|
||||||
var documentContext = TagHelperDocumentContext.Create(tagHelperPrefix, descriptors);
|
var documentContext = TagHelperDocumentContext.Create(tagHelperPrefix, descriptors);
|
||||||
|
|
@ -936,6 +937,7 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
containingTagName,
|
containingTagName,
|
||||||
attributes: Enumerable.Empty<KeyValuePair<string, string>>(),
|
attributes: Enumerable.Empty<KeyValuePair<string, string>>(),
|
||||||
containingParentTagName: containingParentTagName,
|
containingParentTagName: containingParentTagName,
|
||||||
|
containingParentIsTagHelper: containingParentIsTagHelper,
|
||||||
inHTMLSchema: (tag) => tag == "strong" || tag == "b" || tag == "bold" || tag == "li" || tag == "div");
|
inHTMLSchema: (tag) => tag == "strong" || tag == "b" || tag == "bold" || tag == "li" || tag == "div");
|
||||||
|
|
||||||
return completionContext;
|
return completionContext;
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
var service = new DefaultTagHelperFactsService();
|
var service = new DefaultTagHelperFactsService();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var binding = service.GetTagHelperBinding(documentContext, "!a", Enumerable.Empty<KeyValuePair<string, string>>(), parentTag: null);
|
var binding = service.GetTagHelperBinding(documentContext, "!a", Enumerable.Empty<KeyValuePair<string, string>>(), parentTag: null, parentIsTagHelper: false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Null(binding);
|
Assert.Null(binding);
|
||||||
|
|
@ -73,7 +73,7 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var binding = service.GetTagHelperBinding(documentContext, "a", attributes, parentTag: "p");
|
var binding = service.GetTagHelperBinding(documentContext, "a", attributes, parentTag: "p", parentIsTagHelper: false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var descriptor = Assert.Single(binding.Descriptors);
|
var descriptor = Assert.Single(binding.Descriptors);
|
||||||
|
|
@ -109,7 +109,7 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
};
|
};
|
||||||
var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors);
|
var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors);
|
||||||
var service = new DefaultTagHelperFactsService();
|
var service = new DefaultTagHelperFactsService();
|
||||||
var binding = service.GetTagHelperBinding(documentContext, "a", Enumerable.Empty<KeyValuePair<string, string>>(), parentTag: null);
|
var binding = service.GetTagHelperBinding(documentContext, "a", Enumerable.Empty<KeyValuePair<string, string>>(), parentTag: null, parentIsTagHelper: false);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var descriptors = service.GetBoundTagHelperAttributes(documentContext, "asp-route-something", binding);
|
var descriptors = service.GetBoundTagHelperAttributes(documentContext, "asp-route-something", binding);
|
||||||
|
|
@ -144,7 +144,7 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
};
|
};
|
||||||
var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors);
|
var documentContext = TagHelperDocumentContext.Create(string.Empty, documentDescriptors);
|
||||||
var service = new DefaultTagHelperFactsService();
|
var service = new DefaultTagHelperFactsService();
|
||||||
var binding = service.GetTagHelperBinding(documentContext, "input", Enumerable.Empty<KeyValuePair<string, string>>(), parentTag: null);
|
var binding = service.GetTagHelperBinding(documentContext, "input", Enumerable.Empty<KeyValuePair<string, string>>(), parentTag: null, parentIsTagHelper: false);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var descriptors = service.GetBoundTagHelperAttributes(documentContext, "asp-for", binding);
|
var descriptors = service.GetBoundTagHelperAttributes(documentContext, "asp-for", binding);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue