Refined Start tag and End tag structure (dotnet/aspnetcore-tooling#62)

Regenerated baselines\n\nCommit migrated from d54460296f
This commit is contained in:
Ajay Bhargav Baaskaran 2019-01-02 15:32:55 -08:00 committed by GitHub
parent 583113686c
commit 053121e0b7
19 changed files with 1293 additions and 710 deletions

View File

@ -1,65 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Language.Legacy;
using Microsoft.AspNetCore.Razor.Language.Syntax;
namespace Microsoft.AspNetCore.Razor.Language
{
internal class ClassifiedSpanRewriter : SyntaxRewriter
{
public override SyntaxNode VisitMarkupStartTag(MarkupStartTagSyntax node)
{
SpanContext latestSpanContext = null;
var newChildren = SyntaxListBuilder<RazorSyntaxNode>.Create();
var literals = new List<MarkupTextLiteralSyntax>();
foreach (var child in node.Children)
{
if (child is MarkupTextLiteralSyntax literal)
{
literals.Add(literal);
latestSpanContext = literal.GetSpanContext() ?? latestSpanContext;
}
else if (child is MarkupMiscAttributeContentSyntax miscContent)
{
foreach (var contentChild in miscContent.Children)
{
if (contentChild is MarkupTextLiteralSyntax contentLiteral)
{
literals.Add(contentLiteral);
latestSpanContext = contentLiteral.GetSpanContext() ?? latestSpanContext;
}
else
{
// Pop stack
AddLiteralIfExists();
newChildren.Add(contentChild);
}
}
}
else
{
AddLiteralIfExists();
newChildren.Add(child);
}
}
AddLiteralIfExists();
return SyntaxFactory.MarkupStartTag(newChildren.ToList()).Green.CreateRed(node.Parent, node.Position);
void AddLiteralIfExists()
{
if (literals.Count > 0)
{
var mergedLiteral = SyntaxUtilities.MergeTextLiterals(literals.ToArray());
mergedLiteral = mergedLiteral.WithSpanContext(latestSpanContext);
literals.Clear();
latestSpanContext = null;
newChildren.Add(mergedLiteral);
}
}
}
}
}

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language.Legacy;
using Microsoft.AspNetCore.Razor.Language.Syntax;
@ -108,12 +109,26 @@ namespace Microsoft.AspNetCore.Razor.Language
public override void VisitMarkupStartTag(MarkupStartTagSyntax node)
{
WriteBlock(node, BlockKindInternal.Tag, base.VisitMarkupStartTag);
WriteBlock(node, BlockKindInternal.Tag, n =>
{
var children = GetRewrittenMarkupStartTagChildren(node);
foreach (var child in children)
{
Visit(child);
}
});
}
public override void VisitMarkupEndTag(MarkupEndTagSyntax node)
{
WriteBlock(node, BlockKindInternal.Tag, base.VisitMarkupEndTag);
WriteBlock(node, BlockKindInternal.Tag, n =>
{
var children = GetRewrittenMarkupEndTagChildren(node);
foreach (var child in children)
{
Visit(child);
}
});
}
public override void VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax node)
@ -275,5 +290,100 @@ namespace Microsoft.AspNetCore.Razor.Language
var span = new ClassifiedSpanInternal(spanSource, blockSource, kind, _currentBlockKind, acceptedCharacters.Value);
_spans.Add(span);
}
private static SyntaxList<RazorSyntaxNode> GetRewrittenMarkupStartTagChildren(MarkupStartTagSyntax node)
{
// Rewrites the children of the start tag to look like the legacy syntax tree.
if (node.IsMarkupTransition)
{
var tokens = node.DescendantNodes().Where(n => n is SyntaxToken token && !token.IsMissing).Cast<SyntaxToken>().ToArray();
var tokenBuilder = SyntaxListBuilder<SyntaxToken>.Create();
tokenBuilder.AddRange(tokens, 0, tokens.Length);
var markupTransition = SyntaxFactory.MarkupTransition(tokenBuilder.ToList()).Green.CreateRed(node, node.Position);
var spanContext = node.GetSpanContext();
if (spanContext != null)
{
markupTransition = markupTransition.WithSpanContext(spanContext);
}
var builder = new SyntaxListBuilder(1);
builder.Add(markupTransition);
return new SyntaxList<RazorSyntaxNode>(builder.ToListNode().CreateRed(node, node.Position));
}
SpanContext latestSpanContext = null;
var children = node.Children;
var newChildren = new SyntaxListBuilder(children.Count);
var literals = new List<MarkupTextLiteralSyntax>();
foreach (var child in children)
{
if (child is MarkupTextLiteralSyntax literal)
{
literals.Add(literal);
latestSpanContext = literal.GetSpanContext() ?? latestSpanContext;
}
else if (child is MarkupMiscAttributeContentSyntax miscContent)
{
foreach (var contentChild in miscContent.Children)
{
if (contentChild is MarkupTextLiteralSyntax contentLiteral)
{
literals.Add(contentLiteral);
latestSpanContext = contentLiteral.GetSpanContext() ?? latestSpanContext;
}
else
{
// Pop stack
AddLiteralIfExists();
newChildren.Add(contentChild);
}
}
}
else
{
AddLiteralIfExists();
newChildren.Add(child);
}
}
AddLiteralIfExists();
return new SyntaxList<RazorSyntaxNode>(newChildren.ToListNode().CreateRed(node, node.Position));
void AddLiteralIfExists()
{
if (literals.Count > 0)
{
var mergedLiteral = SyntaxUtilities.MergeTextLiterals(literals.ToArray());
mergedLiteral = mergedLiteral.WithSpanContext(latestSpanContext);
literals.Clear();
latestSpanContext = null;
newChildren.Add(mergedLiteral);
}
}
}
private static SyntaxList<RazorSyntaxNode> GetRewrittenMarkupEndTagChildren(MarkupEndTagSyntax node)
{
// Rewrites the children of the end tag to look like the legacy syntax tree.
if (node.IsMarkupTransition)
{
var tokens = node.DescendantNodes().Where(n => n is SyntaxToken token && !token.IsMissing).Cast<SyntaxToken>().ToArray();
var tokenBuilder = SyntaxListBuilder<SyntaxToken>.Create();
tokenBuilder.AddRange(tokens, 0, tokens.Length);
var markupTransition = SyntaxFactory.MarkupTransition(tokenBuilder.ToList()).Green.CreateRed(node, node.Position);
var spanContext = node.GetSpanContext();
if (spanContext != null)
{
markupTransition = markupTransition.WithSpanContext(spanContext);
}
var builder = new SyntaxListBuilder(1);
builder.Add(markupTransition);
return new SyntaxList<RazorSyntaxNode>(builder.ToListNode().CreateRed(node, node.Position));
}
return node.Children;
}
}
}

View File

@ -810,6 +810,22 @@ namespace Microsoft.AspNetCore.Razor.Language
base.VisitMarkupTextLiteral(node);
}
public override void VisitMarkupStartTag(MarkupStartTagSyntax node)
{
foreach (var child in node.Children)
{
Visit(child);
}
}
public override void VisitMarkupEndTag(MarkupEndTagSyntax node)
{
foreach (var child in node.Children)
{
Visit(child);
}
}
public override void VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax node)
{
var info = node.TagHelperInfo;
@ -1110,7 +1126,7 @@ namespace Microsoft.AspNetCore.Razor.Language
Source = BuildSourceSpanFromNode(node),
// Could be empty while the tag is being typed in.
TagName = node.StartTag?.GetTagName() ?? node.EndTag?.GetTagName() ?? string.Empty,
TagName = node.StartTag?.GetTagNameWithOptionalBang() ?? node.EndTag?.GetTagName() ?? string.Empty,
});
base.VisitMarkupElement(node);

View File

@ -322,7 +322,9 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
// Check if the previous span was a transition.
var previousSpan = builder.Count > 0 ? GetLastSpan(builder[builder.Count - 1]) : null;
if (previousSpan != null && previousSpan.Kind == SyntaxKind.MarkupTransition)
if (previousSpan != null &&
((previousSpan is MarkupStartTagSyntax startTag && startTag.IsMarkupTransition) ||
(previousSpan is MarkupEndTagSyntax endTag && endTag.IsMarkupTransition)))
{
var tokens = ReadWhile(
f => (f.Kind == SyntaxKind.Whitespace) || (f.Kind == SyntaxKind.NewLine));
@ -576,179 +578,201 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
tagName = null;
tagMode = MarkupTagMode.Invalid;
isWellFormed = false;
var openAngleToken = EatCurrentToken(); // Accept '<'
var isBangEscape = TryParseBangEscape(out var bangToken);
if (At(SyntaxKind.Text))
{
tagName = CurrentToken.Content;
tagMode = MarkupTagMode.Normal;
if (isBangEscape)
{
// We don't want to group <p> and </!p> together.
tagName = "!" + tagName;
}
}
if (mode == ParseMode.MarkupInCodeBlock &&
_tagTracker.Count == 0 &&
string.Equals(tagName, SyntaxConstants.TextTagName, StringComparison.OrdinalIgnoreCase))
{
// "<text>" tag is special only if it is the outermost tag.
return ParseStartTextTag(openAngleToken, out tagMode, out isWellFormed);
}
var tagNameToken = At(SyntaxKind.Text) ? EatCurrentToken() : SyntaxFactory.MissingToken(SyntaxKind.Text);
var attributes = EmptySyntaxList;
using (var pooledResult = Pool.Allocate<RazorSyntaxNode>())
{
var tagBuilder = pooledResult.Builder;
var attributeBuilder = pooledResult.Builder;
// Parse the contents of a tag like attributes.
ParseAttributes(attributeBuilder);
attributes = attributeBuilder.ToList();
}
AcceptAndMoveNext(); // Accept '<'
var isBangEscape = TryParseBangEscape(tagBuilder);
SyntaxToken forwardSlashToken = null;
if (At(SyntaxKind.ForwardSlash))
{
// This is a self closing tag.
tagMode = MarkupTagMode.SelfClosing;
forwardSlashToken = EatCurrentToken();
}
if (At(SyntaxKind.Text))
var closeAngleToken = SyntaxFactory.MissingToken(SyntaxKind.CloseAngle);
if (mode == ParseMode.MarkupInCodeBlock)
{
if (EndOfFile || !At(SyntaxKind.CloseAngle))
{
tagName = CurrentToken.Content;
tagMode = MarkupTagMode.Normal;
if (isBangEscape)
// Unfinished tag
Context.ErrorSink.OnError(
RazorDiagnosticFactory.CreateParsing_UnfinishedTag(
new SourceSpan(
tagName == null ? tagStartLocation : SourceLocationTracker.Advance(tagStartLocation, "<"),
Math.Max(tagName?.Length ?? 0, 1)),
tagName ?? string.Empty));
}
else
{
if (At(SyntaxKind.CloseAngle))
{
// We don't want to group <p> and </!p> together.
tagName = "!" + tagName;
isWellFormed = true;
closeAngleToken = EatCurrentToken();
}
}
if (mode == ParseMode.MarkupInCodeBlock &&
_tagTracker.Count == 0 &&
string.Equals(tagName, SyntaxConstants.TextTagName, StringComparison.OrdinalIgnoreCase))
{
// "<text>" tag is special only if it is the outermost tag.
return ParseStartTextTag(out tagMode, out isWellFormed);
}
TryAccept(SyntaxKind.Text);
if (At(SyntaxKind.CloseAngle) && mode == ParseMode.MarkupInCodeBlock)
{
// Completed tags in code blocks have no accepted characters.
SpanContext.EditHandler.AcceptedCharacters = AcceptedCharactersInternal.None;
}
// Output open angle and tag name
tagBuilder.Add(OutputAsMarkupLiteral());
// Parse the contents of a tag like attributes.
ParseAttributes(tagBuilder);
if (TryAccept(SyntaxKind.ForwardSlash))
{
// This is a self closing tag.
tagMode = MarkupTagMode.SelfClosing;
}
if (mode == ParseMode.MarkupInCodeBlock)
{
if (EndOfFile || !At(SyntaxKind.CloseAngle))
if (tagMode != MarkupTagMode.SelfClosing && ParserHelpers.VoidElements.Contains(tagName))
{
// Unfinished tag
isWellFormed = false;
Context.ErrorSink.OnError(
RazorDiagnosticFactory.CreateParsing_UnfinishedTag(
new SourceSpan(
tagName == null ? tagStartLocation : SourceLocationTracker.Advance(tagStartLocation, "<"),
Math.Max(tagName?.Length ?? 0, 1)),
tagName ?? string.Empty));
}
else
{
isWellFormed = TryAccept(SyntaxKind.CloseAngle);
// This is a void element.
// Technically, void elements like "meta" are not allowed to have end tags. Just in case they do,
// we need to look ahead at the next set of tokens.
// Completed tags in code blocks have no accepted characters.
SpanContext.EditHandler.AcceptedCharacters = AcceptedCharactersInternal.None;
// Place a bookmark
var bookmark = CurrentStart.AbsoluteIndex;
if (tagMode != MarkupTagMode.SelfClosing && ParserHelpers.VoidElements.Contains(tagName))
// Skip whitespace
ReadWhile(IsSpacingToken(includeNewLines: true));
// Open Angle
if (At(SyntaxKind.OpenAngle) && NextIs(SyntaxKind.ForwardSlash))
{
// This is a void element.
// Technically, void elements like "meta" are not allowed to have end tags. Just in case they do,
// we need to look ahead at the next set of tokens.
// Place a bookmark
var bookmark = CurrentStart.AbsoluteIndex;
// Skip whitespace
var whiteSpace = ReadWhile(IsSpacingToken(includeNewLines: true));
// Open Angle
if (At(SyntaxKind.OpenAngle) && NextIs(SyntaxKind.ForwardSlash))
{
var openAngle = CurrentToken;
NextToken();
Assert(SyntaxKind.ForwardSlash);
var forwardSlash = CurrentToken;
NextToken();
if (!At(SyntaxKind.Text) || !string.Equals(CurrentToken.Content, tagName, StringComparison.OrdinalIgnoreCase))
{
// There is no matching end void tag.
tagMode = MarkupTagMode.Void;
}
}
else
NextToken();
Assert(SyntaxKind.ForwardSlash);
NextToken();
if (!At(SyntaxKind.Text) || !string.Equals(CurrentToken.Content, tagName, StringComparison.OrdinalIgnoreCase))
{
// There is no matching end void tag.
tagMode = MarkupTagMode.Void;
}
// Go back to the bookmark and just finish this tag at the close angle
Context.Source.Position = bookmark;
NextToken();
}
else
{
// There is no matching end void tag.
tagMode = MarkupTagMode.Void;
}
// Go back to the bookmark and just finish this tag at the close angle
Context.Source.Position = bookmark;
NextToken();
}
}
else
{
isWellFormed = TryAccept(SyntaxKind.CloseAngle);
}
// End tag block
tagBuilder.Add(OutputAsMarkupLiteral());
var tagBlock = SyntaxFactory.MarkupStartTag(tagBuilder.ToList());
if (string.Equals(tagName, ScriptTagName, StringComparison.OrdinalIgnoreCase))
{
// If the script tag expects javascript content then we should do minimal parsing until we reach
// the end script tag. Don't want to incorrectly parse a "var tag = '<input />';" as an HTML tag.
if (!ScriptTagExpectsHtml(tagBlock))
{
tagMode = MarkupTagMode.Script;
}
}
return tagBlock;
}
else if (At(SyntaxKind.CloseAngle))
{
isWellFormed = true;
closeAngleToken = EatCurrentToken();
}
// End tag block
var startTag = SyntaxFactory.MarkupStartTag(openAngleToken, bangToken, tagNameToken, attributes, forwardSlashToken, closeAngleToken);
if (string.Equals(tagName, ScriptTagName, StringComparison.OrdinalIgnoreCase))
{
// If the script tag expects javascript content then we should do minimal parsing until we reach
// the end script tag. Don't want to incorrectly parse a "var tag = '<input />';" as an HTML tag.
if (!ScriptTagExpectsHtml(startTag))
{
tagMode = MarkupTagMode.Script;
}
}
return GetNodeWithSpanContext(startTag);
}
private MarkupStartTagSyntax ParseStartTextTag(out MarkupTagMode tagMode, out bool isWellFormed)
private MarkupStartTagSyntax ParseStartTextTag(SyntaxToken openAngleToken, out MarkupTagMode tagMode, out bool isWellFormed)
{
// At this point, we should have already accepted the open angle. We won't get here if the tag is escaped.
tagMode = MarkupTagMode.Normal;
var textLocation = CurrentStart;
Assert(SyntaxKind.Text);
AcceptAndMoveNext();
var tagNameToken = EatCurrentToken();
AcceptWhile(IsSpacingToken(includeNewLines: false));
if (At(SyntaxKind.CloseAngle) ||
(At(SyntaxKind.ForwardSlash) && NextIs(SyntaxKind.CloseAngle)))
using (var pooledResult = Pool.Allocate<RazorSyntaxNode>())
{
if (At(SyntaxKind.ForwardSlash))
var miscAttributeContentBuilder = pooledResult.Builder;
SyntaxToken forwardSlashToken = null;
SyntaxToken closeAngleToken = null;
AcceptWhile(IsSpacingToken(includeNewLines: false));
miscAttributeContentBuilder.Add(OutputAsMarkupLiteral());
if (At(SyntaxKind.CloseAngle) ||
(At(SyntaxKind.ForwardSlash) && NextIs(SyntaxKind.CloseAngle)))
{
tagMode = MarkupTagMode.SelfClosing;
AcceptAndMoveNext(); // '/'
if (At(SyntaxKind.ForwardSlash))
{
tagMode = MarkupTagMode.SelfClosing;
forwardSlashToken = EatCurrentToken();
}
closeAngleToken = EatCurrentToken();
SpanContext.EditHandler.AcceptedCharacters = AcceptedCharactersInternal.None;
}
else
{
Context.ErrorSink.OnError(
RazorDiagnosticFactory.CreateParsing_TextTagCannotContainAttributes(
new SourceSpan(textLocation, contentLength: 4 /* text */)));
RecoverTextTag(out var miscContent, out closeAngleToken);
miscAttributeContentBuilder.Add(miscContent);
}
AcceptAndMoveNext(); // '>'
SpanContext.EditHandler.AcceptedCharacters = AcceptedCharactersInternal.None;
isWellFormed = true;
SpanContext.ChunkGenerator = SpanChunkGenerator.Null;
var startTextTag = SyntaxFactory.MarkupStartTag(
openAngleToken,
bang: null,
name: tagNameToken,
attributes: miscAttributeContentBuilder.ToList(),
forwardSlash: forwardSlashToken,
closeAngle: closeAngleToken);
return GetNodeWithSpanContext(startTextTag).AsMarkupTransition();
}
else
{
Context.ErrorSink.OnError(
RazorDiagnosticFactory.CreateParsing_TextTagCannotContainAttributes(
new SourceSpan(textLocation, contentLength: 4 /* text */)));
RecoverTextTag();
}
isWellFormed = true;
SpanContext.ChunkGenerator = SpanChunkGenerator.Null;
var transition = GetNodeWithSpanContext(SyntaxFactory.MarkupTransition(Output()));
var startTextTag = SyntaxFactory.MarkupStartTag(transition);
return startTextTag;
}
private void RecoverTextTag()
private void RecoverTextTag(out MarkupTextLiteralSyntax miscContent, out SyntaxToken closeAngleToken)
{
// We don't want to skip-to and parse because there shouldn't be anything in the body of text tags.
AcceptUntil(SyntaxKind.CloseAngle, SyntaxKind.NewLine);
miscContent = OutputAsMarkupLiteral();
// Include the close angle in the text tag block if it's there, otherwise just move on
TryAccept(SyntaxKind.CloseAngle);
if (At(SyntaxKind.CloseAngle))
{
closeAngleToken = EatCurrentToken();
}
else
{
closeAngleToken = SyntaxFactory.MissingToken(SyntaxKind.CloseAngle);
}
}
private MarkupEndTagSyntax ParseEndTag(ParseMode mode, out string tagName, out bool isWellFormed)
@ -757,51 +781,61 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
Assert(SyntaxKind.OpenAngle);
tagName = null;
SyntaxToken tagNameToken = null;
using (var pooledResult = Pool.Allocate<RazorSyntaxNode>())
var openAngleToken = EatCurrentToken(); // Accept '<'
var forwardSlashToken = At(SyntaxKind.ForwardSlash) ? EatCurrentToken() : SyntaxFactory.MissingToken(SyntaxKind.ForwardSlash);
// Whitespace here is invalid (according to the spec)
var isBangEscape = TryParseBangEscape(out var bangToken);
if (At(SyntaxKind.Text))
{
var tagBuilder = pooledResult.Builder;
tagName = isBangEscape ? "!" : string.Empty;
tagName += CurrentToken.Content;
AcceptAndMoveNext(); // Accept '<'
TryAccept(SyntaxKind.ForwardSlash);
// Whitespace here is invalid (according to the spec)
var isBangEscape = TryParseBangEscape(tagBuilder);
if (At(SyntaxKind.Text))
if (mode == ParseMode.MarkupInCodeBlock &&
string.Equals(tagName, SyntaxConstants.TextTagName, StringComparison.OrdinalIgnoreCase))
{
tagName = isBangEscape ? "!" : string.Empty;
tagName += CurrentToken.Content;
if (mode == ParseMode.MarkupInCodeBlock &&
string.Equals(tagName, SyntaxConstants.TextTagName, StringComparison.OrdinalIgnoreCase))
// "<text>" tag is special only if it is the outermost tag. We need to figure out if the current end text tag
// matches the outermost start text tag.
var openTextTagCount = 0;
foreach (var tracker in _tagTracker)
{
// "<text>" tag is special only if it is the outermost tag. We need to figure out if the current end text tag
// matches the outermost start text tag.
var openTextTagCount = 0;
foreach (var tracker in _tagTracker)
if (string.Equals(tracker.TagName, SyntaxConstants.TextTagName, StringComparison.OrdinalIgnoreCase))
{
if (string.Equals(tracker.TagName, SyntaxConstants.TextTagName, StringComparison.OrdinalIgnoreCase))
{
openTextTagCount++;
}
}
if (openTextTagCount == 1 &&
string.Equals(_tagTracker.Last().TagName, SyntaxConstants.TextTagName, StringComparison.OrdinalIgnoreCase))
{
// This means there is only one open text tag and it is the outermost tag.
return ParseEndTextTag(out isWellFormed);
openTextTagCount++;
}
}
AcceptAndMoveNext();
if (openTextTagCount == 1 &&
string.Equals(_tagTracker.Last().TagName, SyntaxConstants.TextTagName, StringComparison.OrdinalIgnoreCase))
{
// This means there is only one open text tag and it is the outermost tag.
return ParseEndTextTag(openAngleToken, forwardSlashToken, out isWellFormed);
}
}
TryAccept(SyntaxKind.Whitespace);
tagNameToken = EatCurrentToken();
}
else
{
tagNameToken = SyntaxFactory.MissingToken(SyntaxKind.Text);
}
SyntaxToken closeAngleToken = null;
MarkupMiscAttributeContentSyntax miscAttributeContent = null;
using (var pooledResult = Pool.Allocate<RazorSyntaxNode>())
{
var miscAttributeBuilder = pooledResult.Builder;
AcceptWhile(SyntaxKind.Whitespace);
miscAttributeBuilder.Add(OutputAsMarkupLiteral());
if (mode == ParseMode.MarkupInCodeBlock)
{
// We want to accept malformed end tags as content.
AcceptUntil(SyntaxKind.CloseAngle, SyntaxKind.OpenAngle);
miscAttributeBuilder.Add(OutputAsMarkupLiteral());
if (At(SyntaxKind.CloseAngle))
{
@ -810,42 +844,73 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
}
}
isWellFormed = TryAccept(SyntaxKind.CloseAngle);
// End tag block
tagBuilder.Add(OutputAsMarkupLiteral());
var tagBlock = SyntaxFactory.MarkupEndTag(tagBuilder.ToList());
return tagBlock;
if (miscAttributeBuilder.Count > 0)
{
miscAttributeContent = SyntaxFactory.MarkupMiscAttributeContent(miscAttributeBuilder.ToList());
}
}
if (At(SyntaxKind.CloseAngle))
{
isWellFormed = true;
closeAngleToken = EatCurrentToken();
}
else
{
isWellFormed = false;
closeAngleToken = SyntaxFactory.MissingToken(SyntaxKind.CloseAngle);
}
// End tag block
var endTag = SyntaxFactory.MarkupEndTag(openAngleToken, forwardSlashToken, bangToken, tagNameToken, miscAttributeContent, closeAngleToken);
return GetNodeWithSpanContext(endTag);
}
private MarkupEndTagSyntax ParseEndTextTag(out bool isWellFormed)
private MarkupEndTagSyntax ParseEndTextTag(SyntaxToken openAngleToken, SyntaxToken forwardSlashToken, out bool isWellFormed)
{
// At this point, we should have already accepted the open angle and forward slash. We won't get here if the tag is escaped.
var textLocation = CurrentStart;
Assert(SyntaxKind.Text);
AcceptAndMoveNext();
var tagNameToken = EatCurrentToken();
isWellFormed = TryAccept(SyntaxKind.CloseAngle);
if (!isWellFormed)
MarkupMiscAttributeContentSyntax miscAttributeContent = null;
SyntaxToken closeAngleToken = null;
using (var pooledResult = Pool.Allocate<RazorSyntaxNode>())
{
Context.ErrorSink.OnError(
RazorDiagnosticFactory.CreateParsing_TextTagCannotContainAttributes(
new SourceSpan(textLocation, contentLength: 4 /* text */)));
var miscAttributeBuilder = pooledResult.Builder;
SpanContext.EditHandler.AcceptedCharacters = AcceptedCharactersInternal.Any;
RecoverTextTag();
}
else
{
SpanContext.EditHandler.AcceptedCharacters = AcceptedCharactersInternal.None;
isWellFormed = At(SyntaxKind.CloseAngle);
if (!isWellFormed)
{
Context.ErrorSink.OnError(
RazorDiagnosticFactory.CreateParsing_TextTagCannotContainAttributes(
new SourceSpan(textLocation, contentLength: 4 /* text */)));
SpanContext.EditHandler.AcceptedCharacters = AcceptedCharactersInternal.Any;
RecoverTextTag(out var miscContent, out closeAngleToken);
miscAttributeBuilder.Add(miscContent);
}
else
{
SpanContext.EditHandler.AcceptedCharacters = AcceptedCharactersInternal.None;
closeAngleToken = EatCurrentToken();
}
if (miscAttributeBuilder.Count > 0)
{
miscAttributeContent = SyntaxFactory.MarkupMiscAttributeContent(miscAttributeBuilder.ToList());
}
}
SpanContext.ChunkGenerator = SpanChunkGenerator.Null;
var transition = GetNodeWithSpanContext(SyntaxFactory.MarkupTransition(Output()));
var endTextTag = SyntaxFactory.MarkupEndTag(transition);
return endTextTag;
var endTextTag = SyntaxFactory.MarkupEndTag(
openAngleToken,
forwardSlashToken,
bang: null,
name: tagNameToken,
miscAttributeContent: miscAttributeContent,
closeAngle: closeAngleToken);
return GetNodeWithSpanContext(endTextTag).AsMarkupTransition();
}
private void ParseAttributes(in SyntaxListBuilder<RazorSyntaxNode> builder)
@ -1257,26 +1322,47 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
var tagStart = CurrentStart;
builder.Add(OutputAsMarkupLiteral());
SpanContext.EditHandler.AcceptedCharacters = endTagAcceptedCharacters;
var openAngleToken = EatCurrentToken(); // '<'
var forwardSlashToken = EatCurrentToken(); // '/'
var tagNameToken = EatCurrentToken(); // 'script'
MarkupMiscAttributeContentSyntax miscContent = null;
SyntaxToken closeAngleToken = null;
using (var pooledResult = Pool.Allocate<RazorSyntaxNode>())
{
var tagBuilder = pooledResult.Builder;
SpanContext.EditHandler.AcceptedCharacters = endTagAcceptedCharacters;
var miscAttributeBuilder = pooledResult.Builder;
AcceptAndMoveNext(); // '<'
AcceptAndMoveNext(); // '/'
ParseMarkupNodes(tagBuilder, ParseMode.Text, token => token.Kind == SyntaxKind.CloseAngle);
if (!TryAccept(SyntaxKind.CloseAngle))
ParseMarkupNodes(miscAttributeBuilder, ParseMode.Text, token => token.Kind == SyntaxKind.CloseAngle);
miscAttributeBuilder.Add(OutputAsMarkupLiteral());
if (miscAttributeBuilder.Count > 0)
{
miscContent = SyntaxFactory.MarkupMiscAttributeContent(miscAttributeBuilder.ToList());
}
if (!At(SyntaxKind.CloseAngle))
{
Context.ErrorSink.OnError(
RazorDiagnosticFactory.CreateParsing_UnfinishedTag(
new SourceSpan(SourceLocationTracker.Advance(tagStart, "</"), ScriptTagName.Length),
ScriptTagName));
var closeAngle = SyntaxFactory.MissingToken(SyntaxKind.CloseAngle);
Accept(closeAngle);
closeAngleToken = SyntaxFactory.MissingToken(SyntaxKind.CloseAngle);
}
else
{
closeAngleToken = EatCurrentToken();
}
tagBuilder.Add(OutputAsMarkupLiteral());
endTag = SyntaxFactory.MarkupEndTag(tagBuilder.ToList());
}
endTag = SyntaxFactory.MarkupEndTag(
openAngleToken,
forwardSlashToken,
bang: null,
name: tagNameToken,
miscAttributeContent: miscContent,
closeAngle: closeAngleToken);
endTag = GetNodeWithSpanContext(endTag);
}
var element = SyntaxFactory.MarkupElement(startTag, builder.Consume(), endTag);
@ -1500,13 +1586,9 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
private bool ScriptTagExpectsHtml(MarkupStartTagSyntax tagBlock)
{
MarkupAttributeBlockSyntax typeAttribute = null;
for (var i = 0; i < tagBlock.Children.Count; i++)
for (var i = 0; i < tagBlock.Attributes.Count; i++)
{
var node = tagBlock.Children[i];
if (node.IsToken || node.IsTrivia)
{
continue;
}
var node = tagBlock.Attributes[i];
if (node is MarkupAttributeBlockSyntax attributeBlock &&
attributeBlock.Value.Children.Count > 0 &&
@ -1678,19 +1760,15 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
}
}
private bool TryParseBangEscape(in SyntaxListBuilder<RazorSyntaxNode> builder)
private bool TryParseBangEscape(out SyntaxToken bangToken)
{
bangToken = null;
if (IsBangEscape(lookahead: 0))
{
builder.Add(OutputAsMarkupLiteral());
// Accept the parser escape character '!'.
Assert(SyntaxKind.Bang);
AcceptAndMoveNext();
bangToken = EatCurrentToken();
// Setup the metacode span that we will be outputing.
SpanContext.ChunkGenerator = SpanChunkGenerator.Null;
builder.Add(OutputAsMetaCode(Output()));
return true;
}

View File

@ -100,7 +100,20 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
}
SyntaxNode owner = null;
var children = node.ChildNodes();
IEnumerable<SyntaxNode> children = null;
if (node is MarkupStartTagSyntax startTag)
{
children = startTag.Children;
}
else if (node is MarkupEndTagSyntax endTag)
{
children = endTag.Children;
}
else
{
children = node.ChildNodes();
}
foreach (var child in children)
{
owner = LocateOwner(child, change);
@ -192,7 +205,27 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
foreach (var child in node.DescendantNodes())
{
if (child.IsSpanKind())
if (child is MarkupStartTagSyntax startTag)
{
foreach (var tagChild in startTag.Children)
{
if (tagChild.IsSpanKind())
{
yield return tagChild;
}
}
}
else if (child is MarkupEndTagSyntax endTag)
{
foreach (var tagChild in endTag.Children)
{
if (tagChild.IsSpanKind())
{
yield return tagChild;
}
}
}
else if (child.IsSpanKind())
{
yield return child;
}

View File

@ -16,10 +16,8 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
throw new ArgumentNullException(nameof(syntaxTree));
}
var rewriter = new ClassifiedSpanRewriter();
var rewritten = rewriter.Visit(syntaxTree.Root);
var visitor = new ClassifiedSpanVisitor(syntaxTree.Source);
visitor.Visit(rewritten);
visitor.Visit(syntaxTree.Root);
return visitor.ClassifiedSpans;
}

View File

@ -103,7 +103,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
var startTag = (MarkupStartTagSyntax)Visit(node.StartTag);
if (startTag != null)
{
var tagName = startTag.GetTagName();
var tagName = startTag.GetTagNameWithOptionalBang();
if (TryRewriteTagHelperStart(startTag, out tagHelperStart, out tagHelperInfo))
{
// This is a tag helper.
@ -218,10 +218,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
tagHelperInfo = null;
// Get tag name of the current block
var tagName = startTag.GetTagName();
var tagName = startTag.GetTagNameWithOptionalBang();
// Could not determine tag name, it can't be a TagHelper, continue on and track the element.
if (tagName == null || tagName.StartsWith("!"))
if (string.IsNullOrEmpty(tagName) || tagName.StartsWith("!"))
{
return false;
}
@ -288,7 +288,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
rewritten = null;
var tagName = tagBlock.GetTagName();
// Could not determine tag name, it can't be a TagHelper, continue on and track the element.
if (tagName == null || tagName.StartsWith("!"))
if (string.IsNullOrEmpty(tagName) || tagName.StartsWith("!"))
{
return false;
}
@ -510,22 +510,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
return true;
}
private bool IsPotentialTagHelperStart(string tagName, MarkupStartTagSyntax childBlock)
private bool IsPotentialTagHelperStart(string tagName, MarkupStartTagSyntax startTag)
{
Debug.Assert(childBlock.Children.Count > 0);
var child = childBlock.Children[0];
return !string.Equals(tagName, SyntaxConstants.TextTagName, StringComparison.OrdinalIgnoreCase) ||
child.Kind != SyntaxKind.MarkupTransition;
!startTag.IsMarkupTransition;
}
private bool IsPotentialTagHelperEnd(string tagName, MarkupEndTagSyntax childBlock)
private bool IsPotentialTagHelperEnd(string tagName, MarkupEndTagSyntax endTag)
{
Debug.Assert(childBlock.Children.Count > 0);
var child = childBlock.Children[0];
return !string.Equals(tagName, SyntaxConstants.TextTagName, StringComparison.OrdinalIgnoreCase) ||
child.Kind != SyntaxKind.MarkupTransition;
!endTag.IsMarkupTransition;
}
private static bool IsPartialStartTag(MarkupStartTagSyntax tagBlock)
@ -605,7 +599,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Legacy
private void ValidateParentAllowsPlainStartTag(MarkupStartTagSyntax tagBlock)
{
var tagName = tagBlock.GetTagName();
var tagName = tagBlock.GetTagNameWithOptionalBang();
// Treat partial tags such as '</' which have no tag names as content.
if (string.IsNullOrEmpty(tagName))

View File

@ -860,87 +860,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax
}
}
internal sealed partial class MarkupTagBlockSyntax : RazorBlockSyntax
{
private readonly GreenNode _children;
internal MarkupTagBlockSyntax(SyntaxKind kind, GreenNode children, RazorDiagnostic[] diagnostics, SyntaxAnnotation[] annotations)
: base(kind, diagnostics, annotations)
{
SlotCount = 1;
if (children != null)
{
AdjustFlagsAndWidth(children);
_children = children;
}
}
internal MarkupTagBlockSyntax(SyntaxKind kind, GreenNode children)
: base(kind)
{
SlotCount = 1;
if (children != null)
{
AdjustFlagsAndWidth(children);
_children = children;
}
}
public override SyntaxList<RazorSyntaxNode> Children { get { return new SyntaxList<RazorSyntaxNode>(_children); } }
internal override GreenNode GetSlot(int index)
{
switch (index)
{
case 0: return _children;
default: return null;
}
}
internal override SyntaxNode CreateRed(SyntaxNode parent, int position)
{
return new Syntax.MarkupTagBlockSyntax(this, parent, position);
}
public override TResult Accept<TResult>(SyntaxVisitor<TResult> visitor)
{
return visitor.VisitMarkupTagBlock(this);
}
public override void Accept(SyntaxVisitor visitor)
{
visitor.VisitMarkupTagBlock(this);
}
public MarkupTagBlockSyntax Update(Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax.SyntaxList<RazorSyntaxNode> children)
{
if (children != Children)
{
var newNode = SyntaxFactory.MarkupTagBlock(children);
var diags = GetDiagnostics();
if (diags != null && diags.Length > 0)
newNode = newNode.WithDiagnosticsGreen(diags);
var annotations = GetAnnotations();
if (annotations != null && annotations.Length > 0)
newNode = newNode.WithAnnotationsGreen(annotations);
return newNode;
}
return this;
}
internal override GreenNode SetDiagnostics(RazorDiagnostic[] diagnostics)
{
return new MarkupTagBlockSyntax(Kind, _children, diagnostics, GetAnnotations());
}
internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations)
{
return new MarkupTagBlockSyntax(Kind, _children, GetDiagnostics(), annotations);
}
}
internal sealed partial class MarkupMinimizedAttributeBlockSyntax : MarkupSyntaxNode
{
private readonly MarkupTextLiteralSyntax _namePrefix;
@ -1546,40 +1465,87 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax
}
}
internal sealed partial class MarkupStartTagSyntax : RazorBlockSyntax
internal sealed partial class MarkupStartTagSyntax : MarkupSyntaxNode
{
private readonly GreenNode _children;
private readonly SyntaxToken _openAngle;
private readonly SyntaxToken _bang;
private readonly SyntaxToken _name;
private readonly GreenNode _attributes;
private readonly SyntaxToken _forwardSlash;
private readonly SyntaxToken _closeAngle;
internal MarkupStartTagSyntax(SyntaxKind kind, GreenNode children, RazorDiagnostic[] diagnostics, SyntaxAnnotation[] annotations)
internal MarkupStartTagSyntax(SyntaxKind kind, SyntaxToken openAngle, SyntaxToken bang, SyntaxToken name, GreenNode attributes, SyntaxToken forwardSlash, SyntaxToken closeAngle, RazorDiagnostic[] diagnostics, SyntaxAnnotation[] annotations)
: base(kind, diagnostics, annotations)
{
SlotCount = 1;
if (children != null)
SlotCount = 6;
AdjustFlagsAndWidth(openAngle);
_openAngle = openAngle;
if (bang != null)
{
AdjustFlagsAndWidth(children);
_children = children;
AdjustFlagsAndWidth(bang);
_bang = bang;
}
AdjustFlagsAndWidth(name);
_name = name;
if (attributes != null)
{
AdjustFlagsAndWidth(attributes);
_attributes = attributes;
}
if (forwardSlash != null)
{
AdjustFlagsAndWidth(forwardSlash);
_forwardSlash = forwardSlash;
}
AdjustFlagsAndWidth(closeAngle);
_closeAngle = closeAngle;
}
internal MarkupStartTagSyntax(SyntaxKind kind, GreenNode children)
internal MarkupStartTagSyntax(SyntaxKind kind, SyntaxToken openAngle, SyntaxToken bang, SyntaxToken name, GreenNode attributes, SyntaxToken forwardSlash, SyntaxToken closeAngle)
: base(kind)
{
SlotCount = 1;
if (children != null)
SlotCount = 6;
AdjustFlagsAndWidth(openAngle);
_openAngle = openAngle;
if (bang != null)
{
AdjustFlagsAndWidth(children);
_children = children;
AdjustFlagsAndWidth(bang);
_bang = bang;
}
AdjustFlagsAndWidth(name);
_name = name;
if (attributes != null)
{
AdjustFlagsAndWidth(attributes);
_attributes = attributes;
}
if (forwardSlash != null)
{
AdjustFlagsAndWidth(forwardSlash);
_forwardSlash = forwardSlash;
}
AdjustFlagsAndWidth(closeAngle);
_closeAngle = closeAngle;
}
public override SyntaxList<RazorSyntaxNode> Children { get { return new SyntaxList<RazorSyntaxNode>(_children); } }
public SyntaxToken OpenAngle { get { return _openAngle; } }
public SyntaxToken Bang { get { return _bang; } }
public SyntaxToken Name { get { return _name; } }
public SyntaxList<RazorSyntaxNode> Attributes { get { return new SyntaxList<RazorSyntaxNode>(_attributes); } }
public SyntaxToken ForwardSlash { get { return _forwardSlash; } }
public SyntaxToken CloseAngle { get { return _closeAngle; } }
internal override GreenNode GetSlot(int index)
{
switch (index)
{
case 0: return _children;
case 0: return _openAngle;
case 1: return _bang;
case 2: return _name;
case 3: return _attributes;
case 4: return _forwardSlash;
case 5: return _closeAngle;
default: return null;
}
}
@ -1599,11 +1565,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax
visitor.VisitMarkupStartTag(this);
}
public MarkupStartTagSyntax Update(Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax.SyntaxList<RazorSyntaxNode> children)
public MarkupStartTagSyntax Update(SyntaxToken openAngle, SyntaxToken bang, SyntaxToken name, Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax.SyntaxList<RazorSyntaxNode> attributes, SyntaxToken forwardSlash, SyntaxToken closeAngle)
{
if (children != Children)
if (openAngle != OpenAngle || bang != Bang || name != Name || attributes != Attributes || forwardSlash != ForwardSlash || closeAngle != CloseAngle)
{
var newNode = SyntaxFactory.MarkupStartTag(children);
var newNode = SyntaxFactory.MarkupStartTag(openAngle, bang, name, attributes, forwardSlash, closeAngle);
var diags = GetDiagnostics();
if (diags != null && diags.Length > 0)
newNode = newNode.WithDiagnosticsGreen(diags);
@ -1618,49 +1584,90 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax
internal override GreenNode SetDiagnostics(RazorDiagnostic[] diagnostics)
{
return new MarkupStartTagSyntax(Kind, _children, diagnostics, GetAnnotations());
return new MarkupStartTagSyntax(Kind, _openAngle, _bang, _name, _attributes, _forwardSlash, _closeAngle, diagnostics, GetAnnotations());
}
internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations)
{
return new MarkupStartTagSyntax(Kind, _children, GetDiagnostics(), annotations);
return new MarkupStartTagSyntax(Kind, _openAngle, _bang, _name, _attributes, _forwardSlash, _closeAngle, GetDiagnostics(), annotations);
}
}
internal sealed partial class MarkupEndTagSyntax : RazorBlockSyntax
internal sealed partial class MarkupEndTagSyntax : MarkupSyntaxNode
{
private readonly GreenNode _children;
private readonly SyntaxToken _openAngle;
private readonly SyntaxToken _forwardSlash;
private readonly SyntaxToken _bang;
private readonly SyntaxToken _name;
private readonly MarkupMiscAttributeContentSyntax _miscAttributeContent;
private readonly SyntaxToken _closeAngle;
internal MarkupEndTagSyntax(SyntaxKind kind, GreenNode children, RazorDiagnostic[] diagnostics, SyntaxAnnotation[] annotations)
internal MarkupEndTagSyntax(SyntaxKind kind, SyntaxToken openAngle, SyntaxToken forwardSlash, SyntaxToken bang, SyntaxToken name, MarkupMiscAttributeContentSyntax miscAttributeContent, SyntaxToken closeAngle, RazorDiagnostic[] diagnostics, SyntaxAnnotation[] annotations)
: base(kind, diagnostics, annotations)
{
SlotCount = 1;
if (children != null)
SlotCount = 6;
AdjustFlagsAndWidth(openAngle);
_openAngle = openAngle;
AdjustFlagsAndWidth(forwardSlash);
_forwardSlash = forwardSlash;
if (bang != null)
{
AdjustFlagsAndWidth(children);
_children = children;
AdjustFlagsAndWidth(bang);
_bang = bang;
}
AdjustFlagsAndWidth(name);
_name = name;
if (miscAttributeContent != null)
{
AdjustFlagsAndWidth(miscAttributeContent);
_miscAttributeContent = miscAttributeContent;
}
AdjustFlagsAndWidth(closeAngle);
_closeAngle = closeAngle;
}
internal MarkupEndTagSyntax(SyntaxKind kind, GreenNode children)
internal MarkupEndTagSyntax(SyntaxKind kind, SyntaxToken openAngle, SyntaxToken forwardSlash, SyntaxToken bang, SyntaxToken name, MarkupMiscAttributeContentSyntax miscAttributeContent, SyntaxToken closeAngle)
: base(kind)
{
SlotCount = 1;
if (children != null)
SlotCount = 6;
AdjustFlagsAndWidth(openAngle);
_openAngle = openAngle;
AdjustFlagsAndWidth(forwardSlash);
_forwardSlash = forwardSlash;
if (bang != null)
{
AdjustFlagsAndWidth(children);
_children = children;
AdjustFlagsAndWidth(bang);
_bang = bang;
}
AdjustFlagsAndWidth(name);
_name = name;
if (miscAttributeContent != null)
{
AdjustFlagsAndWidth(miscAttributeContent);
_miscAttributeContent = miscAttributeContent;
}
AdjustFlagsAndWidth(closeAngle);
_closeAngle = closeAngle;
}
public override SyntaxList<RazorSyntaxNode> Children { get { return new SyntaxList<RazorSyntaxNode>(_children); } }
public SyntaxToken OpenAngle { get { return _openAngle; } }
public SyntaxToken ForwardSlash { get { return _forwardSlash; } }
public SyntaxToken Bang { get { return _bang; } }
public SyntaxToken Name { get { return _name; } }
public MarkupMiscAttributeContentSyntax MiscAttributeContent { get { return _miscAttributeContent; } }
public SyntaxToken CloseAngle { get { return _closeAngle; } }
internal override GreenNode GetSlot(int index)
{
switch (index)
{
case 0: return _children;
case 0: return _openAngle;
case 1: return _forwardSlash;
case 2: return _bang;
case 3: return _name;
case 4: return _miscAttributeContent;
case 5: return _closeAngle;
default: return null;
}
}
@ -1680,11 +1687,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax
visitor.VisitMarkupEndTag(this);
}
public MarkupEndTagSyntax Update(Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax.SyntaxList<RazorSyntaxNode> children)
public MarkupEndTagSyntax Update(SyntaxToken openAngle, SyntaxToken forwardSlash, SyntaxToken bang, SyntaxToken name, MarkupMiscAttributeContentSyntax miscAttributeContent, SyntaxToken closeAngle)
{
if (children != Children)
if (openAngle != OpenAngle || forwardSlash != ForwardSlash || bang != Bang || name != Name || miscAttributeContent != MiscAttributeContent || closeAngle != CloseAngle)
{
var newNode = SyntaxFactory.MarkupEndTag(children);
var newNode = SyntaxFactory.MarkupEndTag(openAngle, forwardSlash, bang, name, miscAttributeContent, closeAngle);
var diags = GetDiagnostics();
if (diags != null && diags.Length > 0)
newNode = newNode.WithDiagnosticsGreen(diags);
@ -1699,12 +1706,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax
internal override GreenNode SetDiagnostics(RazorDiagnostic[] diagnostics)
{
return new MarkupEndTagSyntax(Kind, _children, diagnostics, GetAnnotations());
return new MarkupEndTagSyntax(Kind, _openAngle, _forwardSlash, _bang, _name, _miscAttributeContent, _closeAngle, diagnostics, GetAnnotations());
}
internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations)
{
return new MarkupEndTagSyntax(Kind, _children, GetDiagnostics(), annotations);
return new MarkupEndTagSyntax(Kind, _openAngle, _forwardSlash, _bang, _name, _miscAttributeContent, _closeAngle, GetDiagnostics(), annotations);
}
}
@ -3510,11 +3517,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax
return DefaultVisit(node);
}
public virtual TResult VisitMarkupTagBlock(MarkupTagBlockSyntax node)
{
return DefaultVisit(node);
}
public virtual TResult VisitMarkupMinimizedAttributeBlock(MarkupMinimizedAttributeBlockSyntax node)
{
return DefaultVisit(node);
@ -3709,11 +3711,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax
DefaultVisit(node);
}
public virtual void VisitMarkupTagBlock(MarkupTagBlockSyntax node)
{
DefaultVisit(node);
}
public virtual void VisitMarkupMinimizedAttributeBlock(MarkupMinimizedAttributeBlockSyntax node)
{
DefaultVisit(node);
@ -3921,12 +3918,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax
return node.Update(children);
}
public override GreenNode VisitMarkupTagBlock(MarkupTagBlockSyntax node)
{
var children = VisitList(node.Children);
return node.Update(children);
}
public override GreenNode VisitMarkupMinimizedAttributeBlock(MarkupMinimizedAttributeBlockSyntax node)
{
var namePrefix = (MarkupTextLiteralSyntax)Visit(node.NamePrefix);
@ -3976,14 +3967,24 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax
public override GreenNode VisitMarkupStartTag(MarkupStartTagSyntax node)
{
var children = VisitList(node.Children);
return node.Update(children);
var openAngle = (SyntaxToken)Visit(node.OpenAngle);
var bang = (SyntaxToken)Visit(node.Bang);
var name = (SyntaxToken)Visit(node.Name);
var attributes = VisitList(node.Attributes);
var forwardSlash = (SyntaxToken)Visit(node.ForwardSlash);
var closeAngle = (SyntaxToken)Visit(node.CloseAngle);
return node.Update(openAngle, bang, name, attributes, forwardSlash, closeAngle);
}
public override GreenNode VisitMarkupEndTag(MarkupEndTagSyntax node)
{
var children = VisitList(node.Children);
return node.Update(children);
var openAngle = (SyntaxToken)Visit(node.OpenAngle);
var forwardSlash = (SyntaxToken)Visit(node.ForwardSlash);
var bang = (SyntaxToken)Visit(node.Bang);
var name = (SyntaxToken)Visit(node.Name);
var miscAttributeContent = (MarkupMiscAttributeContentSyntax)Visit(node.MiscAttributeContent);
var closeAngle = (SyntaxToken)Visit(node.CloseAngle);
return node.Update(openAngle, forwardSlash, bang, name, miscAttributeContent, closeAngle);
}
public override GreenNode VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax node)
@ -4244,13 +4245,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax
return result;
}
public static MarkupTagBlockSyntax MarkupTagBlock(Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax.SyntaxList<RazorSyntaxNode> children)
{
var result = new MarkupTagBlockSyntax(SyntaxKind.MarkupTagBlock, children.Node);
return result;
}
public static MarkupMinimizedAttributeBlockSyntax MarkupMinimizedAttributeBlock(MarkupTextLiteralSyntax namePrefix, MarkupTextLiteralSyntax name)
{
if (name == null)
@ -4309,18 +4303,112 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax
return result;
}
public static MarkupStartTagSyntax MarkupStartTag(Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax.SyntaxList<RazorSyntaxNode> children)
public static MarkupStartTagSyntax MarkupStartTag(SyntaxToken openAngle, SyntaxToken bang, SyntaxToken name, Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax.SyntaxList<RazorSyntaxNode> attributes, SyntaxToken forwardSlash, SyntaxToken closeAngle)
{
var result = new MarkupStartTagSyntax(SyntaxKind.MarkupStartTag, children.Node);
if (openAngle == null)
throw new ArgumentNullException(nameof(openAngle));
switch (openAngle.Kind)
{
case SyntaxKind.OpenAngle:
break;
default:
throw new ArgumentException("openAngle");
}
if (bang != null)
{
switch (bang.Kind)
{
case SyntaxKind.Bang:
case SyntaxKind.None:
break;
default:
throw new ArgumentException("bang");
}
}
if (name == null)
throw new ArgumentNullException(nameof(name));
switch (name.Kind)
{
case SyntaxKind.Text:
break;
default:
throw new ArgumentException("name");
}
if (forwardSlash != null)
{
switch (forwardSlash.Kind)
{
case SyntaxKind.ForwardSlash:
case SyntaxKind.None:
break;
default:
throw new ArgumentException("forwardSlash");
}
}
if (closeAngle == null)
throw new ArgumentNullException(nameof(closeAngle));
switch (closeAngle.Kind)
{
case SyntaxKind.CloseAngle:
break;
default:
throw new ArgumentException("closeAngle");
}
return result;
return new MarkupStartTagSyntax(SyntaxKind.MarkupStartTag, openAngle, bang, name, attributes.Node, forwardSlash, closeAngle);
}
public static MarkupEndTagSyntax MarkupEndTag(Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax.SyntaxList<RazorSyntaxNode> children)
public static MarkupEndTagSyntax MarkupEndTag(SyntaxToken openAngle, SyntaxToken forwardSlash, SyntaxToken bang, SyntaxToken name, MarkupMiscAttributeContentSyntax miscAttributeContent, SyntaxToken closeAngle)
{
var result = new MarkupEndTagSyntax(SyntaxKind.MarkupEndTag, children.Node);
if (openAngle == null)
throw new ArgumentNullException(nameof(openAngle));
switch (openAngle.Kind)
{
case SyntaxKind.OpenAngle:
break;
default:
throw new ArgumentException("openAngle");
}
if (forwardSlash == null)
throw new ArgumentNullException(nameof(forwardSlash));
switch (forwardSlash.Kind)
{
case SyntaxKind.ForwardSlash:
break;
default:
throw new ArgumentException("forwardSlash");
}
if (bang != null)
{
switch (bang.Kind)
{
case SyntaxKind.Bang:
case SyntaxKind.None:
break;
default:
throw new ArgumentException("bang");
}
}
if (name == null)
throw new ArgumentNullException(nameof(name));
switch (name.Kind)
{
case SyntaxKind.Text:
break;
default:
throw new ArgumentException("name");
}
if (closeAngle == null)
throw new ArgumentNullException(nameof(closeAngle));
switch (closeAngle.Kind)
{
case SyntaxKind.CloseAngle:
break;
default:
throw new ArgumentException("closeAngle");
}
return result;
return new MarkupEndTagSyntax(SyntaxKind.MarkupEndTag, openAngle, forwardSlash, bang, name, miscAttributeContent, closeAngle);
}
public static MarkupTagHelperElementSyntax MarkupTagHelperElement(MarkupTagHelperStartTagSyntax startTag, Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax.SyntaxList<RazorSyntaxNode> body, MarkupTagHelperEndTagSyntax endTag)
@ -4544,7 +4632,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax
typeof(MarkupTextLiteralSyntax),
typeof(MarkupEphemeralTextLiteralSyntax),
typeof(MarkupCommentBlockSyntax),
typeof(MarkupTagBlockSyntax),
typeof(MarkupMinimizedAttributeBlockSyntax),
typeof(MarkupAttributeBlockSyntax),
typeof(MarkupMiscAttributeContentSyntax),

View File

@ -71,12 +71,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
return DefaultVisit(node);
}
/// <summary>Called when the visitor visits a MarkupTagBlockSyntax node.</summary>
public virtual TResult VisitMarkupTagBlock(MarkupTagBlockSyntax node)
{
return DefaultVisit(node);
}
/// <summary>Called when the visitor visits a MarkupMinimizedAttributeBlockSyntax node.</summary>
public virtual TResult VisitMarkupMinimizedAttributeBlock(MarkupMinimizedAttributeBlockSyntax node)
{
@ -308,12 +302,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
DefaultVisit(node);
}
/// <summary>Called when the visitor visits a MarkupTagBlockSyntax node.</summary>
public virtual void VisitMarkupTagBlock(MarkupTagBlockSyntax node)
{
DefaultVisit(node);
}
/// <summary>Called when the visitor visits a MarkupMinimizedAttributeBlockSyntax node.</summary>
public virtual void VisitMarkupMinimizedAttributeBlock(MarkupMinimizedAttributeBlockSyntax node)
{
@ -549,12 +537,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
return node.Update(children);
}
public override SyntaxNode VisitMarkupTagBlock(MarkupTagBlockSyntax node)
{
var children = VisitList(node.Children);
return node.Update(children);
}
public override SyntaxNode VisitMarkupMinimizedAttributeBlock(MarkupMinimizedAttributeBlockSyntax node)
{
var namePrefix = (MarkupTextLiteralSyntax)Visit(node.NamePrefix);
@ -604,14 +586,24 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
public override SyntaxNode VisitMarkupStartTag(MarkupStartTagSyntax node)
{
var children = VisitList(node.Children);
return node.Update(children);
var openAngle = (SyntaxToken)VisitToken(node.OpenAngle);
var bang = (SyntaxToken)VisitToken(node.Bang);
var name = (SyntaxToken)VisitToken(node.Name);
var attributes = VisitList(node.Attributes);
var forwardSlash = (SyntaxToken)VisitToken(node.ForwardSlash);
var closeAngle = (SyntaxToken)VisitToken(node.CloseAngle);
return node.Update(openAngle, bang, name, attributes, forwardSlash, closeAngle);
}
public override SyntaxNode VisitMarkupEndTag(MarkupEndTagSyntax node)
{
var children = VisitList(node.Children);
return node.Update(children);
var openAngle = (SyntaxToken)VisitToken(node.OpenAngle);
var forwardSlash = (SyntaxToken)VisitToken(node.ForwardSlash);
var bang = (SyntaxToken)VisitToken(node.Bang);
var name = (SyntaxToken)VisitToken(node.Name);
var miscAttributeContent = (MarkupMiscAttributeContentSyntax)Visit(node.MiscAttributeContent);
var closeAngle = (SyntaxToken)VisitToken(node.CloseAngle);
return node.Update(openAngle, forwardSlash, bang, name, miscAttributeContent, closeAngle);
}
public override SyntaxNode VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax node)
@ -906,18 +898,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
return SyntaxFactory.MarkupCommentBlock(default(SyntaxList<RazorSyntaxNode>));
}
/// <summary>Creates a new MarkupTagBlockSyntax instance.</summary>
public static MarkupTagBlockSyntax MarkupTagBlock(SyntaxList<RazorSyntaxNode> children)
{
return (MarkupTagBlockSyntax)InternalSyntax.SyntaxFactory.MarkupTagBlock(children.Node.ToGreenList<InternalSyntax.RazorSyntaxNode>()).CreateRed();
}
/// <summary>Creates a new MarkupTagBlockSyntax instance.</summary>
public static MarkupTagBlockSyntax MarkupTagBlock()
{
return SyntaxFactory.MarkupTagBlock(default(SyntaxList<RazorSyntaxNode>));
}
/// <summary>Creates a new MarkupMinimizedAttributeBlockSyntax instance.</summary>
public static MarkupMinimizedAttributeBlockSyntax MarkupMinimizedAttributeBlock(MarkupTextLiteralSyntax namePrefix, MarkupTextLiteralSyntax name)
{
@ -1010,27 +990,100 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
}
/// <summary>Creates a new MarkupStartTagSyntax instance.</summary>
public static MarkupStartTagSyntax MarkupStartTag(SyntaxList<RazorSyntaxNode> children)
public static MarkupStartTagSyntax MarkupStartTag(SyntaxToken openAngle, SyntaxToken bang, SyntaxToken name, SyntaxList<RazorSyntaxNode> attributes, SyntaxToken forwardSlash, SyntaxToken closeAngle)
{
return (MarkupStartTagSyntax)InternalSyntax.SyntaxFactory.MarkupStartTag(children.Node.ToGreenList<InternalSyntax.RazorSyntaxNode>()).CreateRed();
switch (openAngle.Kind)
{
case SyntaxKind.OpenAngle:
break;
default:
throw new ArgumentException("openAngle");
}
switch (bang.Kind)
{
case SyntaxKind.Bang:
case SyntaxKind.None:
break;
default:
throw new ArgumentException("bang");
}
switch (name.Kind)
{
case SyntaxKind.Text:
break;
default:
throw new ArgumentException("name");
}
switch (forwardSlash.Kind)
{
case SyntaxKind.ForwardSlash:
case SyntaxKind.None:
break;
default:
throw new ArgumentException("forwardSlash");
}
switch (closeAngle.Kind)
{
case SyntaxKind.CloseAngle:
break;
default:
throw new ArgumentException("closeAngle");
}
return (MarkupStartTagSyntax)InternalSyntax.SyntaxFactory.MarkupStartTag((Syntax.InternalSyntax.SyntaxToken)openAngle.Green, (Syntax.InternalSyntax.SyntaxToken)bang.Green, (Syntax.InternalSyntax.SyntaxToken)name.Green, attributes.Node.ToGreenList<InternalSyntax.RazorSyntaxNode>(), (Syntax.InternalSyntax.SyntaxToken)forwardSlash.Green, (Syntax.InternalSyntax.SyntaxToken)closeAngle.Green).CreateRed();
}
/// <summary>Creates a new MarkupStartTagSyntax instance.</summary>
public static MarkupStartTagSyntax MarkupStartTag()
public static MarkupStartTagSyntax MarkupStartTag(SyntaxList<RazorSyntaxNode> attributes = default(SyntaxList<RazorSyntaxNode>))
{
return SyntaxFactory.MarkupStartTag(default(SyntaxList<RazorSyntaxNode>));
return SyntaxFactory.MarkupStartTag(SyntaxFactory.Token(SyntaxKind.OpenAngle), default(SyntaxToken), SyntaxFactory.Token(SyntaxKind.Text), attributes, default(SyntaxToken), SyntaxFactory.Token(SyntaxKind.CloseAngle));
}
/// <summary>Creates a new MarkupEndTagSyntax instance.</summary>
public static MarkupEndTagSyntax MarkupEndTag(SyntaxList<RazorSyntaxNode> children)
public static MarkupEndTagSyntax MarkupEndTag(SyntaxToken openAngle, SyntaxToken forwardSlash, SyntaxToken bang, SyntaxToken name, MarkupMiscAttributeContentSyntax miscAttributeContent, SyntaxToken closeAngle)
{
return (MarkupEndTagSyntax)InternalSyntax.SyntaxFactory.MarkupEndTag(children.Node.ToGreenList<InternalSyntax.RazorSyntaxNode>()).CreateRed();
switch (openAngle.Kind)
{
case SyntaxKind.OpenAngle:
break;
default:
throw new ArgumentException("openAngle");
}
switch (forwardSlash.Kind)
{
case SyntaxKind.ForwardSlash:
break;
default:
throw new ArgumentException("forwardSlash");
}
switch (bang.Kind)
{
case SyntaxKind.Bang:
case SyntaxKind.None:
break;
default:
throw new ArgumentException("bang");
}
switch (name.Kind)
{
case SyntaxKind.Text:
break;
default:
throw new ArgumentException("name");
}
switch (closeAngle.Kind)
{
case SyntaxKind.CloseAngle:
break;
default:
throw new ArgumentException("closeAngle");
}
return (MarkupEndTagSyntax)InternalSyntax.SyntaxFactory.MarkupEndTag((Syntax.InternalSyntax.SyntaxToken)openAngle.Green, (Syntax.InternalSyntax.SyntaxToken)forwardSlash.Green, (Syntax.InternalSyntax.SyntaxToken)bang.Green, (Syntax.InternalSyntax.SyntaxToken)name.Green, miscAttributeContent == null ? null : (InternalSyntax.MarkupMiscAttributeContentSyntax)miscAttributeContent.Green, (Syntax.InternalSyntax.SyntaxToken)closeAngle.Green).CreateRed();
}
/// <summary>Creates a new MarkupEndTagSyntax instance.</summary>
public static MarkupEndTagSyntax MarkupEndTag()
public static MarkupEndTagSyntax MarkupEndTag(MarkupMiscAttributeContentSyntax miscAttributeContent = default(MarkupMiscAttributeContentSyntax))
{
return SyntaxFactory.MarkupEndTag(default(SyntaxList<RazorSyntaxNode>));
return SyntaxFactory.MarkupEndTag(SyntaxFactory.Token(SyntaxKind.OpenAngle), SyntaxFactory.Token(SyntaxKind.ForwardSlash), default(SyntaxToken), SyntaxFactory.Token(SyntaxKind.Text), miscAttributeContent, SyntaxFactory.Token(SyntaxKind.CloseAngle));
}
/// <summary>Creates a new MarkupTagHelperElementSyntax instance.</summary>

View File

@ -782,77 +782,6 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
}
}
internal sealed partial class MarkupTagBlockSyntax : RazorBlockSyntax
{
private SyntaxNode _children;
internal MarkupTagBlockSyntax(GreenNode green, SyntaxNode parent, int position)
: base(green, parent, position)
{
}
public override SyntaxList<RazorSyntaxNode> Children
{
get
{
return new SyntaxList<RazorSyntaxNode>(GetRed(ref _children, 0));
}
}
internal override SyntaxNode GetNodeSlot(int index)
{
switch (index)
{
case 0: return GetRedAtZero(ref _children);
default: return null;
}
}
internal override SyntaxNode GetCachedSlot(int index)
{
switch (index)
{
case 0: return _children;
default: return null;
}
}
public override TResult Accept<TResult>(SyntaxVisitor<TResult> visitor)
{
return visitor.VisitMarkupTagBlock(this);
}
public override void Accept(SyntaxVisitor visitor)
{
visitor.VisitMarkupTagBlock(this);
}
public MarkupTagBlockSyntax Update(SyntaxList<RazorSyntaxNode> children)
{
if (children != Children)
{
var newNode = SyntaxFactory.MarkupTagBlock(children);
var annotations = GetAnnotations();
if (annotations != null && annotations.Length > 0)
return newNode.WithAnnotations(annotations);
return newNode;
}
return this;
}
internal override RazorBlockSyntax WithChildrenCore(SyntaxList<RazorSyntaxNode> children) => WithChildren(children);
public new MarkupTagBlockSyntax WithChildren(SyntaxList<RazorSyntaxNode> children)
{
return Update(children);
}
internal override RazorBlockSyntax AddChildrenCore(params RazorSyntaxNode[] items) => AddChildren(items);
public new MarkupTagBlockSyntax AddChildren(params RazorSyntaxNode[] items)
{
return WithChildren(this.Children.AddRange(items));
}
}
internal sealed partial class MarkupMinimizedAttributeBlockSyntax : MarkupSyntaxNode
{
private MarkupTextLiteralSyntax _namePrefix;
@ -1475,38 +1404,77 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
return Update(StartTag, Body, endTag);
}
public MarkupElementSyntax AddStartTagChildren(params RazorSyntaxNode[] items)
public MarkupElementSyntax AddStartTagAttributes(params RazorSyntaxNode[] items)
{
var _startTag = this.StartTag ?? SyntaxFactory.MarkupStartTag();
return this.WithStartTag(_startTag.WithChildren(_startTag.Children.AddRange(items)));
return this.WithStartTag(_startTag.WithAttributes(_startTag.Attributes.AddRange(items)));
}
public MarkupElementSyntax AddBody(params RazorSyntaxNode[] items)
{
return WithBody(this.Body.AddRange(items));
}
public MarkupElementSyntax AddEndTagChildren(params RazorSyntaxNode[] items)
{
var _endTag = this.EndTag ?? SyntaxFactory.MarkupEndTag();
return this.WithEndTag(_endTag.WithChildren(_endTag.Children.AddRange(items)));
}
}
internal sealed partial class MarkupStartTagSyntax : RazorBlockSyntax
internal sealed partial class MarkupStartTagSyntax : MarkupSyntaxNode
{
private SyntaxNode _children;
private SyntaxToken _openAngle;
private SyntaxToken _bang;
private SyntaxToken _name;
private SyntaxNode _attributes;
private SyntaxToken _forwardSlash;
private SyntaxToken _closeAngle;
internal MarkupStartTagSyntax(GreenNode green, SyntaxNode parent, int position)
: base(green, parent, position)
{
}
public override SyntaxList<RazorSyntaxNode> Children
public SyntaxToken OpenAngle
{
get
{
return new SyntaxList<RazorSyntaxNode>(GetRed(ref _children, 0));
return GetRedAtZero(ref _openAngle);
}
}
public SyntaxToken Bang
{
get
{
return GetRed(ref _bang, 1);
}
}
public SyntaxToken Name
{
get
{
return GetRed(ref _name, 2);
}
}
public SyntaxList<RazorSyntaxNode> Attributes
{
get
{
return new SyntaxList<RazorSyntaxNode>(GetRed(ref _attributes, 3));
}
}
public SyntaxToken ForwardSlash
{
get
{
return GetRed(ref _forwardSlash, 4);
}
}
public SyntaxToken CloseAngle
{
get
{
return GetRed(ref _closeAngle, 5);
}
}
@ -1514,7 +1482,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
{
switch (index)
{
case 0: return GetRedAtZero(ref _children);
case 0: return GetRedAtZero(ref _openAngle);
case 1: return GetRed(ref _bang, 1);
case 2: return GetRed(ref _name, 2);
case 3: return GetRed(ref _attributes, 3);
case 4: return GetRed(ref _forwardSlash, 4);
case 5: return GetRed(ref _closeAngle, 5);
default: return null;
}
}
@ -1522,7 +1495,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
{
switch (index)
{
case 0: return _children;
case 0: return _openAngle;
case 1: return _bang;
case 2: return _name;
case 3: return _attributes;
case 4: return _forwardSlash;
case 5: return _closeAngle;
default: return null;
}
}
@ -1537,11 +1515,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
visitor.VisitMarkupStartTag(this);
}
public MarkupStartTagSyntax Update(SyntaxList<RazorSyntaxNode> children)
public MarkupStartTagSyntax Update(SyntaxToken openAngle, SyntaxToken bang, SyntaxToken name, SyntaxList<RazorSyntaxNode> attributes, SyntaxToken forwardSlash, SyntaxToken closeAngle)
{
if (children != Children)
if (openAngle != OpenAngle || bang != Bang || name != Name || attributes != Attributes || forwardSlash != ForwardSlash || closeAngle != CloseAngle)
{
var newNode = SyntaxFactory.MarkupStartTag(children);
var newNode = SyntaxFactory.MarkupStartTag(openAngle, bang, name, attributes, forwardSlash, closeAngle);
var annotations = GetAnnotations();
if (annotations != null && annotations.Length > 0)
return newNode.WithAnnotations(annotations);
@ -1551,33 +1529,101 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
return this;
}
internal override RazorBlockSyntax WithChildrenCore(SyntaxList<RazorSyntaxNode> children) => WithChildren(children);
public new MarkupStartTagSyntax WithChildren(SyntaxList<RazorSyntaxNode> children)
public MarkupStartTagSyntax WithOpenAngle(SyntaxToken openAngle)
{
return Update(children);
return Update(openAngle, Bang, Name, Attributes, ForwardSlash, CloseAngle);
}
internal override RazorBlockSyntax AddChildrenCore(params RazorSyntaxNode[] items) => AddChildren(items);
public new MarkupStartTagSyntax AddChildren(params RazorSyntaxNode[] items)
public MarkupStartTagSyntax WithBang(SyntaxToken bang)
{
return WithChildren(this.Children.AddRange(items));
return Update(OpenAngle, bang, Name, Attributes, ForwardSlash, CloseAngle);
}
public MarkupStartTagSyntax WithName(SyntaxToken name)
{
return Update(OpenAngle, Bang, name, Attributes, ForwardSlash, CloseAngle);
}
public MarkupStartTagSyntax WithAttributes(SyntaxList<RazorSyntaxNode> attributes)
{
return Update(OpenAngle, Bang, Name, attributes, ForwardSlash, CloseAngle);
}
public MarkupStartTagSyntax WithForwardSlash(SyntaxToken forwardSlash)
{
return Update(OpenAngle, Bang, Name, Attributes, forwardSlash, CloseAngle);
}
public MarkupStartTagSyntax WithCloseAngle(SyntaxToken closeAngle)
{
return Update(OpenAngle, Bang, Name, Attributes, ForwardSlash, closeAngle);
}
public MarkupStartTagSyntax AddAttributes(params RazorSyntaxNode[] items)
{
return WithAttributes(this.Attributes.AddRange(items));
}
}
internal sealed partial class MarkupEndTagSyntax : RazorBlockSyntax
internal sealed partial class MarkupEndTagSyntax : MarkupSyntaxNode
{
private SyntaxNode _children;
private SyntaxToken _openAngle;
private SyntaxToken _forwardSlash;
private SyntaxToken _bang;
private SyntaxToken _name;
private MarkupMiscAttributeContentSyntax _miscAttributeContent;
private SyntaxToken _closeAngle;
internal MarkupEndTagSyntax(GreenNode green, SyntaxNode parent, int position)
: base(green, parent, position)
{
}
public override SyntaxList<RazorSyntaxNode> Children
public SyntaxToken OpenAngle
{
get
{
return new SyntaxList<RazorSyntaxNode>(GetRed(ref _children, 0));
return GetRedAtZero(ref _openAngle);
}
}
public SyntaxToken ForwardSlash
{
get
{
return GetRed(ref _forwardSlash, 1);
}
}
public SyntaxToken Bang
{
get
{
return GetRed(ref _bang, 2);
}
}
public SyntaxToken Name
{
get
{
return GetRed(ref _name, 3);
}
}
public MarkupMiscAttributeContentSyntax MiscAttributeContent
{
get
{
return GetRed(ref _miscAttributeContent, 4);
}
}
public SyntaxToken CloseAngle
{
get
{
return GetRed(ref _closeAngle, 5);
}
}
@ -1585,7 +1631,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
{
switch (index)
{
case 0: return GetRedAtZero(ref _children);
case 0: return GetRedAtZero(ref _openAngle);
case 1: return GetRed(ref _forwardSlash, 1);
case 2: return GetRed(ref _bang, 2);
case 3: return GetRed(ref _name, 3);
case 4: return GetRed(ref _miscAttributeContent, 4);
case 5: return GetRed(ref _closeAngle, 5);
default: return null;
}
}
@ -1593,7 +1644,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
{
switch (index)
{
case 0: return _children;
case 0: return _openAngle;
case 1: return _forwardSlash;
case 2: return _bang;
case 3: return _name;
case 4: return _miscAttributeContent;
case 5: return _closeAngle;
default: return null;
}
}
@ -1608,11 +1664,11 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
visitor.VisitMarkupEndTag(this);
}
public MarkupEndTagSyntax Update(SyntaxList<RazorSyntaxNode> children)
public MarkupEndTagSyntax Update(SyntaxToken openAngle, SyntaxToken forwardSlash, SyntaxToken bang, SyntaxToken name, MarkupMiscAttributeContentSyntax miscAttributeContent, SyntaxToken closeAngle)
{
if (children != Children)
if (openAngle != OpenAngle || forwardSlash != ForwardSlash || bang != Bang || name != Name || miscAttributeContent != MiscAttributeContent || closeAngle != CloseAngle)
{
var newNode = SyntaxFactory.MarkupEndTag(children);
var newNode = SyntaxFactory.MarkupEndTag(openAngle, forwardSlash, bang, name, miscAttributeContent, closeAngle);
var annotations = GetAnnotations();
if (annotations != null && annotations.Length > 0)
return newNode.WithAnnotations(annotations);
@ -1622,16 +1678,40 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
return this;
}
internal override RazorBlockSyntax WithChildrenCore(SyntaxList<RazorSyntaxNode> children) => WithChildren(children);
public new MarkupEndTagSyntax WithChildren(SyntaxList<RazorSyntaxNode> children)
public MarkupEndTagSyntax WithOpenAngle(SyntaxToken openAngle)
{
return Update(children);
return Update(openAngle, ForwardSlash, Bang, Name, MiscAttributeContent, CloseAngle);
}
internal override RazorBlockSyntax AddChildrenCore(params RazorSyntaxNode[] items) => AddChildren(items);
public new MarkupEndTagSyntax AddChildren(params RazorSyntaxNode[] items)
public MarkupEndTagSyntax WithForwardSlash(SyntaxToken forwardSlash)
{
return WithChildren(this.Children.AddRange(items));
return Update(OpenAngle, forwardSlash, Bang, Name, MiscAttributeContent, CloseAngle);
}
public MarkupEndTagSyntax WithBang(SyntaxToken bang)
{
return Update(OpenAngle, ForwardSlash, bang, Name, MiscAttributeContent, CloseAngle);
}
public MarkupEndTagSyntax WithName(SyntaxToken name)
{
return Update(OpenAngle, ForwardSlash, Bang, name, MiscAttributeContent, CloseAngle);
}
public MarkupEndTagSyntax WithMiscAttributeContent(MarkupMiscAttributeContentSyntax miscAttributeContent)
{
return Update(OpenAngle, ForwardSlash, Bang, Name, miscAttributeContent, CloseAngle);
}
public MarkupEndTagSyntax WithCloseAngle(SyntaxToken closeAngle)
{
return Update(OpenAngle, ForwardSlash, Bang, Name, MiscAttributeContent, closeAngle);
}
public MarkupEndTagSyntax AddMiscAttributeContentChildren(params RazorSyntaxNode[] items)
{
var _miscAttributeContent = this.MiscAttributeContent ?? SyntaxFactory.MarkupMiscAttributeContent();
return this.WithMiscAttributeContent(_miscAttributeContent.WithChildren(_miscAttributeContent.Children.AddRange(items)));
}
}

View File

@ -0,0 +1,34 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax
{
internal sealed partial class MarkupEndTagSyntax
{
private static readonly string MarkupTransitionKey = "MarkupTransition";
public bool IsMarkupTransition
{
get
{
var annotation = GetAnnotations().FirstOrDefault(n => n.Kind == MarkupTransitionKey);
return annotation != null;
}
}
public MarkupEndTagSyntax AsMarkupTransition()
{
var annotations = new List<SyntaxAnnotation>(GetAnnotations())
{
new SyntaxAnnotation(MarkupTransitionKey, new object())
};
var newGreen = this.WithAnnotationsGreen(annotations.ToArray());
return newGreen;
}
}
}

View File

@ -0,0 +1,34 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax
{
internal sealed partial class MarkupStartTagSyntax
{
private static readonly string MarkupTransitionKey = "MarkupTransition";
public bool IsMarkupTransition
{
get
{
var annotation = GetAnnotations().FirstOrDefault(n => n.Kind == MarkupTransitionKey);
return annotation != null;
}
}
public MarkupStartTagSyntax AsMarkupTransition()
{
var annotations = new List<SyntaxAnnotation>(GetAnnotations())
{
new SyntaxAnnotation(MarkupTransitionKey, new object())
};
var newGreen = this.WithAnnotationsGreen(annotations.ToArray());
return newGreen;
}
}
}

View File

@ -0,0 +1,72 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.Language.Legacy;
namespace Microsoft.AspNetCore.Razor.Language.Syntax
{
internal partial class MarkupEndTagSyntax
{
public bool IsMarkupTransition
{
get
{
return ((InternalSyntax.MarkupEndTagSyntax)Green).IsMarkupTransition;
}
}
public SyntaxList<RazorSyntaxNode> Children => GetLegacyChildren();
public string GetTagName()
{
return Name.IsMissing ? string.Empty : Bang?.Content + Name.Content;
}
private SyntaxList<RazorSyntaxNode> GetLegacyChildren()
{
// This method returns the children of this end tag in legacy format.
// This is needed to generate the same classified spans as the legacy syntax tree.
var builder = new SyntaxListBuilder(3);
var tokens = SyntaxListBuilder<SyntaxToken>.Create();
var context = this.GetSpanContext();
if (!OpenAngle.IsMissing)
{
tokens.Add(OpenAngle);
}
if (!ForwardSlash.IsMissing)
{
tokens.Add(ForwardSlash);
}
if (Bang != null)
{
// The prefix of an end tag(E.g '|</|!foo>') will have 'Any' accepted characters if a bang exists.
var acceptsAnyContext = new SpanContext(context.ChunkGenerator, SpanEditHandler.CreateDefault());
acceptsAnyContext.EditHandler.AcceptedCharacters = AcceptedCharactersInternal.Any;
builder.Add(SyntaxFactory.MarkupTextLiteral(tokens.Consume()).WithSpanContext(acceptsAnyContext));
tokens.Add(Bang);
var acceptsNoneContext = new SpanContext(context.ChunkGenerator, SpanEditHandler.CreateDefault());
acceptsNoneContext.EditHandler.AcceptedCharacters = AcceptedCharactersInternal.None;
builder.Add(SyntaxFactory.RazorMetaCode(tokens.Consume()).WithSpanContext(acceptsNoneContext));
}
if (!Name.IsMissing)
{
tokens.Add(Name);
}
if (MiscAttributeContent?.Children != null && MiscAttributeContent.Children.Count > 0)
{
foreach (var content in MiscAttributeContent.Children)
{
tokens.AddRange(((MarkupTextLiteralSyntax)content).LiteralTokens);
}
}
if (!CloseAngle.IsMissing)
{
tokens.Add(CloseAngle);
}
builder.Add(SyntaxFactory.MarkupTextLiteral(tokens.Consume()).WithSpanContext(context));
return new SyntaxList<RazorSyntaxNode>(builder.ToListNode().CreateRed(this, Position));
}
}
}

View File

@ -0,0 +1,98 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.Language.Legacy;
namespace Microsoft.AspNetCore.Razor.Language.Syntax
{
internal partial class MarkupStartTagSyntax
{
public bool IsMarkupTransition
{
get
{
return ((InternalSyntax.MarkupStartTagSyntax)Green).IsMarkupTransition;
}
}
public SyntaxList<RazorSyntaxNode> Children => GetLegacyChildren();
public string GetTagNameWithOptionalBang()
{
return Name.IsMissing ? string.Empty : Bang?.Content + Name.Content;
}
public bool IsSelfClosing()
{
return ForwardSlash != null &&
!ForwardSlash.IsMissing &&
!CloseAngle.IsMissing;
}
public bool IsVoidElement()
{
return ParserHelpers.VoidElements.Contains(Name.Content);
}
private SyntaxList<RazorSyntaxNode> GetLegacyChildren()
{
// This method returns the children of this start tag in legacy format.
// This is needed to generate the same classified spans as the legacy syntax tree.
var builder = new SyntaxListBuilder(5);
var tokens = SyntaxListBuilder<SyntaxToken>.Create();
var context = this.GetSpanContext();
// We want to know if this tag contains non-whitespace attribute content to set the appropriate AcceptedCharacters.
// The prefix of a start tag(E.g '|<foo| attr>') will have 'Any' accepted characters if non-whitespace attribute content exists.
var acceptsAnyContext = new SpanContext(context.ChunkGenerator, SpanEditHandler.CreateDefault());
acceptsAnyContext.EditHandler.AcceptedCharacters = AcceptedCharactersInternal.Any;
var containsAttributesContent = false;
foreach (var attribute in Attributes)
{
if (!string.IsNullOrWhiteSpace(attribute.GetContent()))
{
containsAttributesContent = true;
break;
}
}
if (!OpenAngle.IsMissing)
{
tokens.Add(OpenAngle);
}
if (Bang != null)
{
builder.Add(SyntaxFactory.MarkupTextLiteral(tokens.Consume()).WithSpanContext(acceptsAnyContext));
tokens.Add(Bang);
var acceptsNoneContext = new SpanContext(context.ChunkGenerator, SpanEditHandler.CreateDefault());
acceptsNoneContext.EditHandler.AcceptedCharacters = AcceptedCharactersInternal.None;
builder.Add(SyntaxFactory.RazorMetaCode(tokens.Consume()).WithSpanContext(acceptsNoneContext));
}
if (!Name.IsMissing)
{
tokens.Add(Name);
}
builder.Add(SyntaxFactory.MarkupTextLiteral(tokens.Consume()).WithSpanContext(containsAttributesContent ? acceptsAnyContext : context));
builder.AddRange(Attributes);
if (ForwardSlash != null)
{
tokens.Add(ForwardSlash);
}
if (!CloseAngle.IsMissing)
{
tokens.Add(CloseAngle);
}
if (tokens.Count > 0)
{
builder.Add(SyntaxFactory.MarkupTextLiteral(tokens.Consume()).WithSpanContext(context));
}
return new SyntaxList<RazorSyntaxNode>(builder.ToListNode().CreateRed(this, Position));
}
}
}

View File

@ -65,10 +65,6 @@
<Kind Name="MarkupCommentBlock" />
<Field Name="Children" Type="SyntaxList&lt;RazorSyntaxNode&gt;" Override="true" />
</Node>
<Node Name="MarkupTagBlockSyntax" Base="RazorBlockSyntax">
<Kind Name="MarkupTagBlock" />
<Field Name="Children" Type="SyntaxList&lt;RazorSyntaxNode&gt;" Override="true" />
</Node>
<Node Name="MarkupMinimizedAttributeBlockSyntax" Base="MarkupSyntaxNode">
<Kind Name="MarkupMinimizedAttributeBlock" />
<Field Name="NamePrefix" Type="MarkupTextLiteralSyntax" Optional="true" />
@ -106,13 +102,43 @@
<Field Name="Body" Type="SyntaxList&lt;RazorSyntaxNode&gt;" />
<Field Name="EndTag" Type="MarkupEndTagSyntax" Optional="true" />
</Node>
<Node Name="MarkupStartTagSyntax" Base="RazorBlockSyntax">
<Node Name="MarkupStartTagSyntax" Base="MarkupSyntaxNode">
<Kind Name="MarkupStartTag" />
<Field Name="Children" Type="SyntaxList&lt;RazorSyntaxNode&gt;" Override="true" />
<Field Name="OpenAngle" Type="SyntaxToken">
<Kind Name="OpenAngle" />
</Field>
<Field Name="Bang" Type="SyntaxToken" Optional="true">
<Kind Name="Bang" />
</Field>
<Field Name="Name" Type="SyntaxToken">
<Kind Name="Text" />
</Field>
<Field Name="Attributes" Type="SyntaxList&lt;RazorSyntaxNode&gt;" />
<Field Name="ForwardSlash" Type="SyntaxToken" Optional="true">
<Kind Name="ForwardSlash" />
</Field>
<Field Name="CloseAngle" Type="SyntaxToken">
<Kind Name="CloseAngle" />
</Field>
</Node>
<Node Name="MarkupEndTagSyntax" Base="RazorBlockSyntax">
<Node Name="MarkupEndTagSyntax" Base="MarkupSyntaxNode">
<Kind Name="MarkupEndTag" />
<Field Name="Children" Type="SyntaxList&lt;RazorSyntaxNode&gt;" Override="true" />
<Field Name="OpenAngle" Type="SyntaxToken">
<Kind Name="OpenAngle" />
</Field>
<Field Name="ForwardSlash" Type="SyntaxToken">
<Kind Name="ForwardSlash" />
</Field>
<Field Name="Bang" Type="SyntaxToken" Optional="true">
<Kind Name="Bang" />
</Field>
<Field Name="Name" Type="SyntaxToken">
<Kind Name="Text" />
</Field>
<Field Name="MiscAttributeContent" Type="MarkupMiscAttributeContentSyntax" Optional="true" />
<Field Name="CloseAngle" Type="SyntaxToken">
<Kind Name="CloseAngle" />
</Field>
</Node>
<Node Name="MarkupTagHelperElementSyntax" Base="MarkupSyntaxNode">
<Kind Name="MarkupTagHelperElement" />

View File

@ -75,6 +75,13 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
return _builder.ToList();
}
public SyntaxList<TNode> Consume()
{
var list = ToList();
Clear();
return list;
}
public static implicit operator SyntaxListBuilder(SyntaxListBuilder<TNode> builder)
{
return builder._builder;

View File

@ -220,109 +220,5 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
var content = string.Concat(tokens.Select(t => t.Content));
return content;
}
public static string GetTagName(this MarkupTagBlockSyntax tagBlock)
{
return GetTagNameCore(tagBlock);
}
public static string GetTagName(this MarkupStartTagSyntax startTag)
{
return GetTagNameCore(startTag);
}
public static string GetTagName(this MarkupEndTagSyntax endTag)
{
return GetTagNameCore(endTag);
}
private static string GetTagNameCore(RazorBlockSyntax tagBlock)
{
if (tagBlock == null)
{
throw new ArgumentNullException(nameof(tagBlock));
}
MarkupTextLiteralSyntax nameLiteral = null;
var isBangTag = false;
if (tagBlock.Children.Count > 0 && tagBlock.Children[0] is MarkupTextLiteralSyntax firstChild)
{
if (firstChild.GetContent().StartsWith("<") &&
tagBlock.Children.Count >= 3 &&
tagBlock.Children[1] is RazorMetaCodeSyntax &&
tagBlock.Children[2] is MarkupTextLiteralSyntax potentialBangTagName)
{
isBangTag = true;
nameLiteral = potentialBangTagName;
}
else
{
nameLiteral = firstChild;
}
}
if (nameLiteral == null)
{
return null;
}
SyntaxToken textToken = null;
for (var i = 0; i < nameLiteral.LiteralTokens.Count; i++)
{
var token = nameLiteral.LiteralTokens[i];
if (token != null &&
(token.Kind == SyntaxKind.Whitespace || token.Kind == SyntaxKind.Text))
{
textToken = token;
break;
}
}
if (textToken == null)
{
return null;
}
var name = textToken.Kind == SyntaxKind.Whitespace ? null : textToken.Content;
if (name != null && isBangTag)
{
name = "!" + name;
}
return name;
}
public static bool IsSelfClosing(this MarkupTagBlockSyntax tagBlock)
{
return IsSelfClosingCore(tagBlock);
}
public static bool IsSelfClosing(this MarkupStartTagSyntax startTag)
{
return IsSelfClosingCore(startTag);
}
private static bool IsSelfClosingCore(RazorBlockSyntax tagBlock)
{
if (tagBlock == null)
{
throw new ArgumentNullException(nameof(tagBlock));
}
var lastChild = tagBlock.ChildNodes().LastOrDefault();
return lastChild?.GetContent().EndsWith("/>", StringComparison.Ordinal) ?? false;
}
public static bool IsVoidElement(this MarkupStartTagSyntax startTag)
{
if (startTag == null)
{
throw new ArgumentNullException(nameof(startTag));
}
return ParserHelpers.VoidElements.Contains(startTag.GetTagName());
}
}
}

View File

@ -151,6 +151,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
{
WriteTagHelperAttributeInfo(minimizedTagHelperAttribute.TagHelperAttributeInfo);
}
else if (node is MarkupStartTagSyntax startTag)
{
if (startTag.IsMarkupTransition)
{
WriteSeparator();
Write("MarkupTransition");
}
}
else if (node is MarkupEndTagSyntax endTag)
{
if (endTag.IsMarkupTransition)
{
WriteSeparator();
Write("MarkupTransition");
}
}
if (ShouldDisplayNodeContent(node))
{

View File

@ -67,6 +67,22 @@ namespace Microsoft.AspNetCore.Razor.Language.Syntax
{
WriteTagHelperAttributeInfo(minimizedTagHelperAttribute.TagHelperAttributeInfo);
}
else if (node is MarkupStartTagSyntax startTag)
{
if (startTag.IsMarkupTransition)
{
WriteSeparator();
Write("MarkupTransition");
}
}
else if (node is MarkupEndTagSyntax endTag)
{
if (endTag.IsMarkupTransition)
{
WriteSeparator();
Write("MarkupTransition");
}
}
if (ShouldDisplayNodeContent(node))
{