Added new BlockType - HtmlComment

Updated the HtmlMarkupParser to understand the HtmlCOmments, and treat those as blocks.
This commit is contained in:
Artak Mkrtchyan 2018-02-15 18:15:34 -08:00
parent a940a4cd91
commit ad8485addd
No known key found for this signature in database
GPG Key ID: 64D580ACBA8CA645
6 changed files with 165 additions and 34 deletions

View File

@ -18,6 +18,8 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
// Special // Special
Comment = 8, Comment = 8,
Tag = 9 Tag = 9,
HtmlComment = 10
} }
} }

View File

@ -207,6 +207,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
if (last != null) if (last != null)
{ {
Accept(last); Accept(last);
if (At(HtmlSymbolType.OpenAngle) && last.Type == HtmlSymbolType.Text)
{
Output(SpanKindInternal.Markup);
}
} }
} }
@ -494,26 +498,34 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
if (CurrentSymbol.Type == HtmlSymbolType.DoubleHyphen) if (CurrentSymbol.Type == HtmlSymbolType.DoubleHyphen)
{ {
AcceptAndMoveNext(); using (Context.Builder.StartBlock(BlockKindInternal.HtmlComment))
Span.EditHandler.AcceptedCharacters = AcceptedCharactersInternal.Any;
while (!EndOfFile)
{ {
SkipToAndParseCode(HtmlSymbolType.DoubleHyphen); AcceptAndMoveNext();
if (At(HtmlSymbolType.DoubleHyphen))
Span.EditHandler.AcceptedCharacters = AcceptedCharactersInternal.Any;
while (!EndOfFile)
{ {
AcceptWhile(HtmlSymbolType.DoubleHyphen); SkipToAndParseCode(HtmlSymbolType.DoubleHyphen);
if (At(HtmlSymbolType.DoubleHyphen))
if (At(HtmlSymbolType.Text) &&
string.Equals(CurrentSymbol.Content, "-", StringComparison.Ordinal))
{ {
AcceptAndMoveNext(); AcceptWhile(HtmlSymbolType.DoubleHyphen);
}
if (At(HtmlSymbolType.CloseAngle)) if (At(HtmlSymbolType.Text) &&
{ string.Equals(CurrentSymbol.Content, "-", StringComparison.Ordinal))
AcceptAndMoveNext(); {
return true; AcceptAndMoveNext();
}
if (At(HtmlSymbolType.CloseAngle))
{
// This is the end of a comment block
Accept(this.CurrentSymbol);
Output(SpanKindInternal.Markup);
NextToken();
//AcceptAndMoveNext();
return true;
}
} }
} }
} }
@ -1476,6 +1488,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
AcceptAndMoveNext(); // Accept '<' AcceptAndMoveNext(); // Accept '<'
BangTag(); BangTag();
return; return;
} }

View File

@ -488,7 +488,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
private void ValidateParentAllowsContent(Span child, ErrorSink errorSink) private void ValidateParentAllowsContent(Span child, ErrorSink errorSink)
{ {
if (HasAllowedChildren() && !IsComment(child)) if (HasAllowedChildren() && !IsComment(child) && child.Kind != SpanKindInternal.Transition && child.Kind != SpanKindInternal.Code)
{ {
var content = child.Content; var content = child.Content;
if (!string.IsNullOrWhiteSpace(content)) if (!string.IsNullOrWhiteSpace(content))
@ -817,14 +817,18 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
return relevantSymbol.Type == HtmlSymbolType.ForwardSlash; return relevantSymbol.Type == HtmlSymbolType.ForwardSlash;
} }
private static bool IsComment(Span span) internal static bool IsComment(Span span)
{ {
bool isHtmlComment = span.Content?.StartsWith("<!--") == true; Block currentBlock = span.Parent;
bool isRazorComment = span.Parent?.Type == BlockKindInternal.Comment; while (currentBlock != null && currentBlock.Type != BlockKindInternal.Comment && currentBlock.Type != BlockKindInternal.HtmlComment)
{
currentBlock = currentBlock.Parent;
}
return isHtmlComment || isRazorComment; return currentBlock != null;
} }
private static void EnsureTagBlock(Block tagBlock) private static void EnsureTagBlock(Block tagBlock)
{ {
Debug.Assert(tagBlock.Type == BlockKindInternal.Tag); Debug.Assert(tagBlock.Type == BlockKindInternal.Tag);

View File

@ -19,6 +19,8 @@ namespace Microsoft.VisualStudio.Editor.Razor
// Special // Special
Comment, Comment,
Tag Tag,
HtmlComment
} }
} }

View File

@ -1109,12 +1109,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
} }
[Fact] [Fact]
public void Rewrite_AllowsHtmlCommentsAsChildren() public void Rewrite_AllowsSimpleHtmlCommentsAsChildren()
{ {
// Arrangestring documentContent, // Arrangestring documentContent,
IEnumerable<string> allowedChildren = new List<string> { "b" }; IEnumerable<string> allowedChildren = new List<string> { "b" };
string literal = "asdf"; string literal = "asdf";
string commentOutput = $"<!--Hello World-->"; string commentOutput = "<!--Hello World-->";
string expectedOutput = $"<p><b>{literal}</b>{commentOutput}</p>"; string expectedOutput = $"<p><b>{literal}</b>{commentOutput}</p>";
var pTagHelperBuilder = TagHelperDescriptorBuilder var pTagHelperBuilder = TagHelperDescriptorBuilder
@ -1138,7 +1138,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
blockFactory.MarkupTagBlock("<b>"), blockFactory.MarkupTagBlock("<b>"),
factory.Markup(literal), factory.Markup(literal),
blockFactory.MarkupTagBlock("</b>"), blockFactory.MarkupTagBlock("</b>"),
factory.Markup(commentOutput))); new HtmlCommentBlock(factory.Markup(commentOutput))));
// Act & Assert // Act & Assert
EvaluateData( EvaluateData(
@ -1148,6 +1148,58 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
Array.Empty<RazorDiagnostic>()); Array.Empty<RazorDiagnostic>());
} }
[Fact]
public void Rewrite_FailsForContentWithCommentsAsChildren()
{
// Arrangestring documentContent,
Func<string, string, string, int, int, RazorDiagnostic> nestedTagError =
(childName, parentName, allowed, location, length) =>
RazorDiagnosticFactory.CreateTagHelper_InvalidNestedTag(
new SourceSpan(absoluteIndex: location, lineIndex: 0, characterIndex: location, length: length), childName, parentName, allowed);
Func<string, string, int, int, RazorDiagnostic> nestedContentError =
(parentName, allowed, location, length) =>
RazorDiagnosticFactory.CreateTagHelper_CannotHaveNonTagContent(
new SourceSpan(absoluteIndex: location, lineIndex: 0, characterIndex: location, length: length), parentName, allowed);
IEnumerable<string> allowedChildren = new List<string> { "b" };
string comment1 = "Hello";
string literal = "asdf";
string comment2 = "World";
string expectedOutput = $"<p><!--{comment1}-->{literal}<!--{comment2}--></p>";
var pTagHelperBuilder = TagHelperDescriptorBuilder
.Create("PTagHelper", "SomeAssembly")
.TagMatchingRuleDescriptor(rule => rule.RequireTagName("p"));
foreach (var childTag in allowedChildren)
{
pTagHelperBuilder.AllowChildTag(childTag);
}
var descriptors = new TagHelperDescriptor[]
{
pTagHelperBuilder.Build()
};
var factory = new SpanFactory();
var blockFactory = new BlockFactory(factory);
var expectedMarkup = new MarkupBlock(
new MarkupTagHelperBlock("p",
new HtmlCommentBlock(factory.Markup($"<!--{comment1}-->")),
factory.Markup(literal),
new HtmlCommentBlock(factory.Markup($"<!--{comment2}-->"))));
// Act & Assert
EvaluateData(
descriptors,
expectedOutput,
expectedMarkup,
new[]
{
nestedContentError("p", "b", 15, 4),
});
}
[Fact] [Fact]
public void Rewrite_AllowsRazorCommentsAsChildren() public void Rewrite_AllowsRazorCommentsAsChildren()
{ {
@ -1193,6 +1245,54 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
Array.Empty<RazorDiagnostic>()); Array.Empty<RazorDiagnostic>());
} }
[Fact]
public void Rewrite_AllowsRazorMarkupInHtmlComment()
{
// Arrangestring documentContent,
IEnumerable<string> allowedChildren = new List<string> { "b" };
string literal = "asdf";
string part1 = "<!--Hello ";
string part2 = "World";
string part3 = "-->";
string expectedOutput = $"<p><b>{literal}</b>{part1}@{part2}{part3}</p>";
var pTagHelperBuilder = TagHelperDescriptorBuilder
.Create("PTagHelper", "SomeAssembly")
.TagMatchingRuleDescriptor(rule => rule.RequireTagName("p"));
foreach (var childTag in allowedChildren)
{
pTagHelperBuilder.AllowChildTag(childTag);
}
var descriptors = new TagHelperDescriptor[]
{
pTagHelperBuilder.Build()
};
var factory = new SpanFactory();
var blockFactory = new BlockFactory(factory);
var expectedMarkup = new MarkupBlock(
new MarkupTagHelperBlock("p",
blockFactory.MarkupTagBlock("<b>"),
factory.Markup(literal),
blockFactory.MarkupTagBlock("</b>"),
new HtmlCommentBlock(factory.Markup(part1),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code(part2)
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharactersInternal.NonWhiteSpace)),
factory.Markup(part3))));
// Act & Assert
EvaluateData(
descriptors,
expectedOutput,
expectedMarkup,
Array.Empty<RazorDiagnostic>());
}
[Fact] [Fact]
public void Rewrite_UnderstandsNullTagNameWithAllowedChildrenForCatchAll() public void Rewrite_UnderstandsNullTagNameWithAllowedChildrenForCatchAll()
{ {
@ -3993,7 +4093,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
new MarkupBlock( new MarkupBlock(
new MarkupTagBlock( new MarkupTagBlock(
factory.Markup("<foo>")), factory.Markup("<foo>")),
factory.Markup("<!-- Hello World -->"), new HtmlCommentBlock( factory.Markup("<!-- Hello World -->")),
new MarkupTagBlock( new MarkupTagBlock(
factory.Markup("</foo>"))) factory.Markup("</foo>")))
}; };
@ -4003,13 +4103,13 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
new MarkupBlock( new MarkupBlock(
new MarkupTagBlock( new MarkupTagBlock(
factory.Markup("<foo>")), factory.Markup("<foo>")),
factory.Markup("<!-- "), new HtmlCommentBlock(factory.Markup("<!-- "),
new ExpressionBlock( new ExpressionBlock(
factory.CodeTransition(), factory.CodeTransition(),
factory.Code("foo") factory.Code("foo")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords) .AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharactersInternal.NonWhiteSpace)), .Accepts(AcceptedCharactersInternal.NonWhiteSpace)),
factory.Markup(" -->"), factory.Markup(" -->")),
new MarkupTagBlock( new MarkupTagBlock(
factory.Markup("</foo>"))) factory.Markup("</foo>")))
}; };

View File

@ -217,4 +217,14 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
{ {
} }
} }
internal class HtmlCommentBlock : Block
{
private const BlockKindInternal ThisBlockKind = BlockKindInternal.HtmlComment;
public HtmlCommentBlock(params SyntaxTreeNode[] children)
: base(ThisBlockKind, children, ParentChunkGenerator.Null)
{
}
}
} }