diff --git a/src/Microsoft.AspNetCore.Razor/Chunks/Generators/AddTagHelperChunkGenerator.cs b/src/Microsoft.AspNetCore.Razor/Chunks/Generators/AddTagHelperChunkGenerator.cs
index 463e4424e0..17bac2b7b5 100644
--- a/src/Microsoft.AspNetCore.Razor/Chunks/Generators/AddTagHelperChunkGenerator.cs
+++ b/src/Microsoft.AspNetCore.Razor/Chunks/Generators/AddTagHelperChunkGenerator.cs
@@ -12,8 +12,6 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
///
public class AddTagHelperChunkGenerator : SpanChunkGenerator
{
- private readonly string _lookupText;
-
///
/// Initializes a new instance of .
///
@@ -22,9 +20,14 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
///
public AddTagHelperChunkGenerator(string lookupText)
{
- _lookupText = lookupText;
+ LookupText = lookupText;
}
+ ///
+ /// Gets the text used to look up s that should be added.
+ ///
+ public string LookupText { get; }
+
///
/// Generates s.
///
@@ -35,7 +38,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
/// the current chunk generation process.
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
{
- context.ChunkTreeBuilder.AddAddTagHelperChunk(_lookupText, target);
+ context.ChunkTreeBuilder.AddAddTagHelperChunk(LookupText, target);
}
///
@@ -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);
}
///
@@ -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;
}
diff --git a/src/Microsoft.AspNetCore.Razor/Chunks/Generators/RemoveTagHelperChunkGenerator.cs b/src/Microsoft.AspNetCore.Razor/Chunks/Generators/RemoveTagHelperChunkGenerator.cs
index c41dcd95e9..1c57cc6cb0 100644
--- a/src/Microsoft.AspNetCore.Razor/Chunks/Generators/RemoveTagHelperChunkGenerator.cs
+++ b/src/Microsoft.AspNetCore.Razor/Chunks/Generators/RemoveTagHelperChunkGenerator.cs
@@ -12,8 +12,6 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
///
public class RemoveTagHelperChunkGenerator : SpanChunkGenerator
{
- private readonly string _lookupText;
-
///
/// Initializes a new instance of .
///
@@ -22,9 +20,14 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
///
public RemoveTagHelperChunkGenerator(string lookupText)
{
- _lookupText = lookupText;
+ LookupText = lookupText;
}
+ ///
+ /// Text used to look up s that should be removed.
+ ///
+ public string LookupText { get; }
+
///
/// Generates s.
///
@@ -35,7 +38,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
/// the current chunk generation process.
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
{
- context.ChunkTreeBuilder.AddRemoveTagHelperChunk(_lookupText, target);
+ context.ChunkTreeBuilder.AddRemoveTagHelperChunk(LookupText, target);
}
///
@@ -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);
}
///
@@ -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;
}
diff --git a/src/Microsoft.AspNetCore.Razor/Chunks/Generators/TagHelperPrefixDirectiveChunkGenerator.cs b/src/Microsoft.AspNetCore.Razor/Chunks/Generators/TagHelperPrefixDirectiveChunkGenerator.cs
index ab59b1827d..d9fc198f6d 100644
--- a/src/Microsoft.AspNetCore.Razor/Chunks/Generators/TagHelperPrefixDirectiveChunkGenerator.cs
+++ b/src/Microsoft.AspNetCore.Razor/Chunks/Generators/TagHelperPrefixDirectiveChunkGenerator.cs
@@ -13,8 +13,6 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
///
public class TagHelperPrefixDirectiveChunkGenerator : SpanChunkGenerator
{
- private readonly string _prefix;
-
///
/// Initializes a new instance of .
///
@@ -23,9 +21,14 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
///
public TagHelperPrefixDirectiveChunkGenerator(string prefix)
{
- _prefix = prefix;
+ Prefix = prefix;
}
+ ///
+ /// Text used as a required prefix when matching HTML.
+ ///
+ public string Prefix { get; }
+
///
/// Generates s.
///
@@ -36,7 +39,7 @@ namespace Microsoft.AspNetCore.Razor.Chunks.Generators
/// the current chunk generation process.
public override void GenerateChunk(Span target, ChunkGeneratorContext context)
{
- context.ChunkTreeBuilder.AddTagHelperPrefixDirectiveChunk(_prefix, target);
+ context.ChunkTreeBuilder.AddTagHelperPrefixDirectiveChunk(Prefix, target);
}
///
@@ -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);
}
///
@@ -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;
}
diff --git a/src/Microsoft.AspNetCore.Razor/Parser/TagHelpers/TagHelperDirectiveSpanVisitor.cs b/src/Microsoft.AspNetCore.Razor/Parser/TagHelpers/TagHelperDirectiveSpanVisitor.cs
index 294ef30368..b3bdb043f4 100644
--- a/src/Microsoft.AspNetCore.Razor/Parser/TagHelpers/TagHelperDirectiveSpanVisitor.cs
+++ b/src/Microsoft.AspNetCore.Razor/Parser/TagHelpers/TagHelperDirectiveSpanVisitor.cs
@@ -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);
diff --git a/test/Microsoft.AspNetCore.Razor.Test/TagHelpers/TagHelperDirectiveSpanVisitorTest.cs b/test/Microsoft.AspNetCore.Razor.Test/TagHelpers/TagHelperDirectiveSpanVisitorTest.cs
index e61f2d70a7..e18f75e464 100644
--- a/test/Microsoft.AspNetCore.Razor.Test/TagHelpers/TagHelperDirectiveSpanVisitorTest.cs
+++ b/test/Microsoft.AspNetCore.Razor.Test/TagHelpers/TagHelperDirectiveSpanVisitorTest.cs
@@ -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>
+ {
+ {
+ 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 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()
{