Update `TagHelperDirectiveSpanVisitor` to properly capture TagHelper directive text.
- Added a test with optional quotes for each of the `TagHelperDirectiveDescriptor`s, add, remove and prefix. #744
This commit is contained in:
parent
cacd16fa85
commit
80ebb4a068
|
|
@ -12,8 +12,6 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AddTagHelperChunkGenerator : SpanChunkGenerator
|
public class AddTagHelperChunkGenerator : SpanChunkGenerator
|
||||||
{
|
{
|
||||||
private readonly string _lookupText;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of <see cref="AddTagHelperChunkGenerator"/>.
|
/// Initializes a new instance of <see cref="AddTagHelperChunkGenerator"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -22,9 +20,14 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
|
||||||
/// </param>
|
/// </param>
|
||||||
public AddTagHelperChunkGenerator(string lookupText)
|
public AddTagHelperChunkGenerator(string lookupText)
|
||||||
{
|
{
|
||||||
_lookupText = lookupText;
|
LookupText = lookupText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the text used to look up <see cref="Compilation.TagHelpers.TagHelperDescriptor"/>s that should be added.
|
||||||
|
/// </summary>
|
||||||
|
public string LookupText { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates <see cref="AddTagHelperChunk"/>s.
|
/// Generates <see cref="AddTagHelperChunk"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -35,7 +38,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
|
||||||
/// the current chunk generation process.</param>
|
/// the current chunk generation process.</param>
|
||||||
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
|
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
|
||||||
{
|
{
|
||||||
context.ChunkTreeBuilder.AddAddTagHelperChunk(_lookupText, target);
|
context.ChunkTreeBuilder.AddAddTagHelperChunk(LookupText, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -43,7 +46,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
|
||||||
{
|
{
|
||||||
var other = obj as AddTagHelperChunkGenerator;
|
var other = obj as AddTagHelperChunkGenerator;
|
||||||
return base.Equals(other) &&
|
return base.Equals(other) &&
|
||||||
string.Equals(_lookupText, other._lookupText, StringComparison.Ordinal);
|
string.Equals(LookupText, other.LookupText, StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -51,7 +54,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
|
||||||
{
|
{
|
||||||
var combiner = HashCodeCombiner.Start();
|
var combiner = HashCodeCombiner.Start();
|
||||||
combiner.Add(base.GetHashCode());
|
combiner.Add(base.GetHashCode());
|
||||||
combiner.Add(_lookupText, StringComparer.Ordinal);
|
combiner.Add(LookupText, StringComparer.Ordinal);
|
||||||
|
|
||||||
return combiner.CombinedHash;
|
return combiner.CombinedHash;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,6 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class RemoveTagHelperChunkGenerator : SpanChunkGenerator
|
public class RemoveTagHelperChunkGenerator : SpanChunkGenerator
|
||||||
{
|
{
|
||||||
private readonly string _lookupText;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of <see cref="RemoveTagHelperChunkGenerator"/>.
|
/// Initializes a new instance of <see cref="RemoveTagHelperChunkGenerator"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -22,9 +20,14 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
|
||||||
/// </param>
|
/// </param>
|
||||||
public RemoveTagHelperChunkGenerator(string lookupText)
|
public RemoveTagHelperChunkGenerator(string lookupText)
|
||||||
{
|
{
|
||||||
_lookupText = lookupText;
|
LookupText = lookupText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Text used to look up <see cref="Compilation.TagHelpers.TagHelperDescriptor"/>s that should be removed.
|
||||||
|
/// </summary>
|
||||||
|
public string LookupText { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates <see cref="RemoveTagHelperChunk"/>s.
|
/// Generates <see cref="RemoveTagHelperChunk"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -35,7 +38,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
|
||||||
/// the current chunk generation process.</param>
|
/// the current chunk generation process.</param>
|
||||||
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
|
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
|
||||||
{
|
{
|
||||||
context.ChunkTreeBuilder.AddRemoveTagHelperChunk(_lookupText, target);
|
context.ChunkTreeBuilder.AddRemoveTagHelperChunk(LookupText, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -43,7 +46,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
|
||||||
{
|
{
|
||||||
var other = obj as RemoveTagHelperChunkGenerator;
|
var other = obj as RemoveTagHelperChunkGenerator;
|
||||||
return base.Equals(other) &&
|
return base.Equals(other) &&
|
||||||
string.Equals(_lookupText, other._lookupText, StringComparison.Ordinal);
|
string.Equals(LookupText, other.LookupText, StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -51,7 +54,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
|
||||||
{
|
{
|
||||||
var combiner = HashCodeCombiner.Start();
|
var combiner = HashCodeCombiner.Start();
|
||||||
combiner.Add(base.GetHashCode());
|
combiner.Add(base.GetHashCode());
|
||||||
combiner.Add(_lookupText, StringComparer.Ordinal);
|
combiner.Add(LookupText, StringComparer.Ordinal);
|
||||||
|
|
||||||
return combiner.CombinedHash;
|
return combiner.CombinedHash;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,6 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TagHelperPrefixDirectiveChunkGenerator : SpanChunkGenerator
|
public class TagHelperPrefixDirectiveChunkGenerator : SpanChunkGenerator
|
||||||
{
|
{
|
||||||
private readonly string _prefix;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of <see cref="TagHelperPrefixDirectiveChunkGenerator"/>.
|
/// Initializes a new instance of <see cref="TagHelperPrefixDirectiveChunkGenerator"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -23,9 +21,14 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
|
||||||
/// </param>
|
/// </param>
|
||||||
public TagHelperPrefixDirectiveChunkGenerator(string prefix)
|
public TagHelperPrefixDirectiveChunkGenerator(string prefix)
|
||||||
{
|
{
|
||||||
_prefix = prefix;
|
Prefix = prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Text used as a required prefix when matching HTML.
|
||||||
|
/// </summary>
|
||||||
|
public string Prefix { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates <see cref="TagHelperPrefixDirectiveChunk"/>s.
|
/// Generates <see cref="TagHelperPrefixDirectiveChunk"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -36,7 +39,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
|
||||||
/// the current chunk generation process.</param>
|
/// the current chunk generation process.</param>
|
||||||
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
|
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
|
||||||
{
|
{
|
||||||
context.ChunkTreeBuilder.AddTagHelperPrefixDirectiveChunk(_prefix, target);
|
context.ChunkTreeBuilder.AddTagHelperPrefixDirectiveChunk(Prefix, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -44,7 +47,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
|
||||||
{
|
{
|
||||||
var other = obj as TagHelperPrefixDirectiveChunkGenerator;
|
var other = obj as TagHelperPrefixDirectiveChunkGenerator;
|
||||||
return base.Equals(other) &&
|
return base.Equals(other) &&
|
||||||
string.Equals(_prefix, other._prefix, StringComparison.Ordinal);
|
string.Equals(Prefix, other.Prefix, StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -52,7 +55,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
|
||||||
{
|
{
|
||||||
var combiner = HashCodeCombiner.Start();
|
var combiner = HashCodeCombiner.Start();
|
||||||
combiner.Add(base.GetHashCode());
|
combiner.Add(base.GetHashCode());
|
||||||
combiner.Add(_prefix, StringComparer.Ordinal);
|
combiner.Add(Prefix, StringComparer.Ordinal);
|
||||||
|
|
||||||
return combiner.CombinedHash;
|
return combiner.CombinedHash;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,18 +87,27 @@ namespace Microsoft.AspNetCore.Razor.Parser.TagHelpers
|
||||||
throw new ArgumentNullException(nameof(span));
|
throw new ArgumentNullException(nameof(span));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string directiveText;
|
||||||
TagHelperDirectiveType directiveType;
|
TagHelperDirectiveType directiveType;
|
||||||
if (span.ChunkGenerator is AddTagHelperChunkGenerator)
|
|
||||||
|
var addTagHelperChunkGenerator = span.ChunkGenerator as AddTagHelperChunkGenerator;
|
||||||
|
var removeTagHelperChunkGenerator = span.ChunkGenerator as RemoveTagHelperChunkGenerator;
|
||||||
|
var tagHelperPrefixChunkGenerator = span.ChunkGenerator as TagHelperPrefixDirectiveChunkGenerator;
|
||||||
|
|
||||||
|
if (addTagHelperChunkGenerator != null)
|
||||||
{
|
{
|
||||||
directiveType = TagHelperDirectiveType.AddTagHelper;
|
directiveType = TagHelperDirectiveType.AddTagHelper;
|
||||||
|
directiveText = addTagHelperChunkGenerator.LookupText;
|
||||||
}
|
}
|
||||||
else if (span.ChunkGenerator is RemoveTagHelperChunkGenerator)
|
else if (removeTagHelperChunkGenerator != null)
|
||||||
{
|
{
|
||||||
directiveType = TagHelperDirectiveType.RemoveTagHelper;
|
directiveType = TagHelperDirectiveType.RemoveTagHelper;
|
||||||
|
directiveText = removeTagHelperChunkGenerator.LookupText;
|
||||||
}
|
}
|
||||||
else if (span.ChunkGenerator is TagHelperPrefixDirectiveChunkGenerator)
|
else if (tagHelperPrefixChunkGenerator != null)
|
||||||
{
|
{
|
||||||
directiveType = TagHelperDirectiveType.TagHelperPrefix;
|
directiveType = TagHelperDirectiveType.TagHelperPrefix;
|
||||||
|
directiveText = tagHelperPrefixChunkGenerator.Prefix;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -106,7 +115,7 @@ namespace Microsoft.AspNetCore.Razor.Parser.TagHelpers
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var directiveText = span.Content.Trim();
|
directiveText = directiveText.Trim();
|
||||||
var startOffset = span.Content.IndexOf(directiveText, StringComparison.Ordinal);
|
var startOffset = span.Content.IndexOf(directiveText, StringComparison.Ordinal);
|
||||||
var offsetContent = span.Content.Substring(0, startOffset);
|
var offsetContent = span.Content.Substring(0, startOffset);
|
||||||
var offsetTextLocation = SourceLocation.Advance(span.Start, offsetContent);
|
var offsetTextLocation = SourceLocation.Advance(span.Start, offsetContent);
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Razor.Parser;
|
||||||
using Microsoft.AspNetCore.Razor.Parser.SyntaxTree;
|
using Microsoft.AspNetCore.Razor.Parser.SyntaxTree;
|
||||||
using Microsoft.AspNetCore.Razor.Parser.TagHelpers;
|
using Microsoft.AspNetCore.Razor.Parser.TagHelpers;
|
||||||
using Microsoft.AspNetCore.Razor.Test.Framework;
|
using Microsoft.AspNetCore.Razor.Test.Framework;
|
||||||
|
using Microsoft.AspNetCore.Razor.Tokenizer;
|
||||||
using Microsoft.Extensions.Internal;
|
using Microsoft.Extensions.Internal;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -18,6 +19,109 @@ namespace Microsoft.AspNetCore.Razor.Compilation.TagHelpers
|
||||||
{
|
{
|
||||||
private static readonly SpanFactory Factory = SpanFactory.CreateCsHtml();
|
private static readonly SpanFactory Factory = SpanFactory.CreateCsHtml();
|
||||||
|
|
||||||
|
public static TheoryData QuotedTagHelperDirectivesData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var factory = new SpanFactory
|
||||||
|
{
|
||||||
|
MarkupTokenizerFactory = doc => new HtmlTokenizer(doc),
|
||||||
|
CodeTokenizerFactory = doc => new CSharpTokenizer(doc),
|
||||||
|
};
|
||||||
|
|
||||||
|
// document, expectedDescriptors
|
||||||
|
return new TheoryData<MarkupBlock, IEnumerable<TagHelperDirectiveDescriptor>>
|
||||||
|
{
|
||||||
|
{
|
||||||
|
new MarkupBlock(factory.Code("\"*, someAssembly\"").AsAddTagHelper("*, someAssembly")),
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new TagHelperDirectiveDescriptor
|
||||||
|
{
|
||||||
|
DirectiveText = "*, someAssembly",
|
||||||
|
DirectiveType = TagHelperDirectiveType.AddTagHelper
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new MarkupBlock(factory.Code("\"*, someAssembly\"").AsRemoveTagHelper("*, someAssembly")),
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new TagHelperDirectiveDescriptor
|
||||||
|
{
|
||||||
|
DirectiveText = "*, someAssembly",
|
||||||
|
DirectiveType = TagHelperDirectiveType.RemoveTagHelper
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new MarkupBlock(factory.Code("\"th:\"").AsTagHelperPrefixDirective("th:")),
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new TagHelperDirectiveDescriptor
|
||||||
|
{
|
||||||
|
DirectiveText = "th:",
|
||||||
|
DirectiveType = TagHelperDirectiveType.TagHelperPrefix
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new MarkupBlock(factory.Code(" \"*, someAssembly \" ").AsAddTagHelper("*, someAssembly ")),
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new TagHelperDirectiveDescriptor
|
||||||
|
{
|
||||||
|
DirectiveText = "*, someAssembly",
|
||||||
|
DirectiveType = TagHelperDirectiveType.AddTagHelper
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new MarkupBlock(factory.Code(" \"*, someAssembly \" ").AsRemoveTagHelper("*, someAssembly ")),
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new TagHelperDirectiveDescriptor
|
||||||
|
{
|
||||||
|
DirectiveText = "*, someAssembly",
|
||||||
|
DirectiveType = TagHelperDirectiveType.RemoveTagHelper
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new MarkupBlock(factory.Code(" \" th :\"").AsTagHelperPrefixDirective(" th :")),
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new TagHelperDirectiveDescriptor
|
||||||
|
{
|
||||||
|
DirectiveText = "th :",
|
||||||
|
DirectiveType = TagHelperDirectiveType.TagHelperPrefix
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(QuotedTagHelperDirectivesData))]
|
||||||
|
public void GetDescriptors_LocatesQuotedTagHelperDirectives_CreatesDirectiveDescriptors(
|
||||||
|
MarkupBlock document,
|
||||||
|
IEnumerable<TagHelperDirectiveDescriptor> expectedDescriptors)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var resolver = new TestTagHelperDescriptorResolver();
|
||||||
|
var tagHelperDirectiveSpanVisitor = new TagHelperDirectiveSpanVisitor(resolver, new ErrorSink());
|
||||||
|
|
||||||
|
// Act
|
||||||
|
tagHelperDirectiveSpanVisitor.GetDescriptors(document);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(
|
||||||
|
expectedDescriptors,
|
||||||
|
resolver.DirectiveDescriptors,
|
||||||
|
TagHelperDirectiveDescriptorComparer.Default);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetDescriptors_InvokesResolveOnceForAllDirectives()
|
public void GetDescriptors_InvokesResolveOnceForAllDirectives()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue