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:
N. Taylor Mullen 2016-05-17 16:45:17 -07:00
parent cacd16fa85
commit 80ebb4a068
5 changed files with 144 additions and 22 deletions

View File

@ -12,8 +12,6 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
/// </summary>
public class AddTagHelperChunkGenerator : SpanChunkGenerator
{
private readonly string _lookupText;
/// <summary>
/// Initializes a new instance of <see cref="AddTagHelperChunkGenerator"/>.
/// </summary>
@ -22,9 +20,14 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
/// </param>
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>
/// Generates <see cref="AddTagHelperChunk"/>s.
/// </summary>
@ -35,7 +38,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
/// the current chunk generation process.</param>
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
{
context.ChunkTreeBuilder.AddAddTagHelperChunk(_lookupText, target);
context.ChunkTreeBuilder.AddAddTagHelperChunk(LookupText, target);
}
/// <inheritdoc />
@ -43,7 +46,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
{
var other = obj as AddTagHelperChunkGenerator;
return base.Equals(other) &&
string.Equals(_lookupText, other._lookupText, StringComparison.Ordinal);
string.Equals(LookupText, other.LookupText, StringComparison.Ordinal);
}
/// <inheritdoc />
@ -51,7 +54,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
{
var combiner = HashCodeCombiner.Start();
combiner.Add(base.GetHashCode());
combiner.Add(_lookupText, StringComparer.Ordinal);
combiner.Add(LookupText, StringComparer.Ordinal);
return combiner.CombinedHash;
}

View File

@ -12,8 +12,6 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
/// </summary>
public class RemoveTagHelperChunkGenerator : SpanChunkGenerator
{
private readonly string _lookupText;
/// <summary>
/// Initializes a new instance of <see cref="RemoveTagHelperChunkGenerator"/>.
/// </summary>
@ -22,9 +20,14 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
/// </param>
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>
/// Generates <see cref="RemoveTagHelperChunk"/>s.
/// </summary>
@ -35,7 +38,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
/// the current chunk generation process.</param>
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
{
context.ChunkTreeBuilder.AddRemoveTagHelperChunk(_lookupText, target);
context.ChunkTreeBuilder.AddRemoveTagHelperChunk(LookupText, target);
}
/// <inheritdoc />
@ -43,7 +46,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
{
var other = obj as RemoveTagHelperChunkGenerator;
return base.Equals(other) &&
string.Equals(_lookupText, other._lookupText, StringComparison.Ordinal);
string.Equals(LookupText, other.LookupText, StringComparison.Ordinal);
}
/// <inheritdoc />
@ -51,7 +54,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
{
var combiner = HashCodeCombiner.Start();
combiner.Add(base.GetHashCode());
combiner.Add(_lookupText, StringComparer.Ordinal);
combiner.Add(LookupText, StringComparer.Ordinal);
return combiner.CombinedHash;
}

View File

@ -13,8 +13,6 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
/// </summary>
public class TagHelperPrefixDirectiveChunkGenerator : SpanChunkGenerator
{
private readonly string _prefix;
/// <summary>
/// Initializes a new instance of <see cref="TagHelperPrefixDirectiveChunkGenerator"/>.
/// </summary>
@ -23,9 +21,14 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
/// </param>
public TagHelperPrefixDirectiveChunkGenerator(string prefix)
{
_prefix = prefix;
Prefix = prefix;
}
/// <summary>
/// Text used as a required prefix when matching HTML.
/// </summary>
public string Prefix { get; }
/// <summary>
/// Generates <see cref="TagHelperPrefixDirectiveChunk"/>s.
/// </summary>
@ -36,7 +39,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
/// the current chunk generation process.</param>
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
{
context.ChunkTreeBuilder.AddTagHelperPrefixDirectiveChunk(_prefix, target);
context.ChunkTreeBuilder.AddTagHelperPrefixDirectiveChunk(Prefix, target);
}
/// <inheritdoc />
@ -44,7 +47,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
{
var other = obj as TagHelperPrefixDirectiveChunkGenerator;
return base.Equals(other) &&
string.Equals(_prefix, other._prefix, StringComparison.Ordinal);
string.Equals(Prefix, other.Prefix, StringComparison.Ordinal);
}
/// <inheritdoc />
@ -52,7 +55,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
{
var combiner = HashCodeCombiner.Start();
combiner.Add(base.GetHashCode());
combiner.Add(_prefix, StringComparer.Ordinal);
combiner.Add(Prefix, StringComparer.Ordinal);
return combiner.CombinedHash;
}

View File

@ -87,18 +87,27 @@ namespace Microsoft.AspNetCore.Razor.Parser.TagHelpers
throw new ArgumentNullException(nameof(span));
}
string directiveText;
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;
directiveText = addTagHelperChunkGenerator.LookupText;
}
else if (span.ChunkGenerator is RemoveTagHelperChunkGenerator)
else if (removeTagHelperChunkGenerator != null)
{
directiveType = TagHelperDirectiveType.RemoveTagHelper;
directiveText = removeTagHelperChunkGenerator.LookupText;
}
else if (span.ChunkGenerator is TagHelperPrefixDirectiveChunkGenerator)
else if (tagHelperPrefixChunkGenerator != null)
{
directiveType = TagHelperDirectiveType.TagHelperPrefix;
directiveText = tagHelperPrefixChunkGenerator.Prefix;
}
else
{
@ -106,7 +115,7 @@ namespace Microsoft.AspNetCore.Razor.Parser.TagHelpers
return;
}
var directiveText = span.Content.Trim();
directiveText = directiveText.Trim();
var startOffset = span.Content.IndexOf(directiveText, StringComparison.Ordinal);
var offsetContent = span.Content.Substring(0, startOffset);
var offsetTextLocation = SourceLocation.Advance(span.Start, offsetContent);

View File

@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Razor.Parser;
using Microsoft.AspNetCore.Razor.Parser.SyntaxTree;
using Microsoft.AspNetCore.Razor.Parser.TagHelpers;
using Microsoft.AspNetCore.Razor.Test.Framework;
using Microsoft.AspNetCore.Razor.Tokenizer;
using Microsoft.Extensions.Internal;
using Moq;
using Xunit;
@ -18,6 +19,109 @@ namespace Microsoft.AspNetCore.Razor.Compilation.TagHelpers
{
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]
public void GetDescriptors_InvokesResolveOnceForAllDirectives()
{