private static SyntaxNode?GetStartOrEndTagName(SyntaxNode node) { return(node switch { MarkupTagHelperStartTagSyntax tagHelperStartTag => tagHelperStartTag.Name, MarkupTagHelperEndTagSyntax tagHelperEndTag => tagHelperEndTag.Name, _ => null });
public override void VisitMarkupTagHelperEndTag(MarkupTagHelperEndTagSyntax node) { if (ClassifyTagName((MarkupTagHelperElementSyntax)node.Parent)) { var result = CreateSemanticRange(node.Name, SyntaxKind.MarkupTagHelperEndTag); AddNode(result); } base.VisitMarkupTagHelperEndTag(node); }
public override void VisitMarkupTagHelperEndTag(MarkupTagHelperEndTagSyntax node) { if (ClassifyTagName((MarkupTagHelperElementSyntax)node.Parent)) { var result = new SyntaxResult(node.Name, SyntaxKind.MarkupTagHelperEndTag, _razorCodeDocument); _syntaxNodes.Add(result); } base.VisitMarkupTagHelperEndTag(node); }
public override void VisitMarkupTagHelperEndTag(MarkupTagHelperEndTagSyntax node) { WriteBlock(node, FormattingBlockKind.Tag, n => { foreach (var child in n.Children) { Visit(child); } }); }
public override void VisitMarkupTagHelperEndTag(MarkupTagHelperEndTagSyntax node) { AddSemanticRange(node.OpenAngle); AddSemanticRange(node.ForwardSlash); if (ClassifyTagName((MarkupTagHelperElementSyntax)node.Parent)) { AddSemanticRange(node.Name, SyntaxKind.MarkupTagHelperEndTag); } else { AddSemanticRange(node.Name, SyntaxKind.MarkupElement); } base.VisitMarkupTagHelperEndTag(node); AddSemanticRange(node.CloseAngle); }
public override void VisitMarkupTagHelperEndTag(MarkupTagHelperEndTagSyntax node) { AddSemanticRange(node.OpenAngle, RazorSemanticTokensLegend.MarkupTagDelimiter); AddSemanticRange(node.ForwardSlash, RazorSemanticTokensLegend.MarkupTagDelimiter); if (node.Bang != null) { AddSemanticRange(node.Bang, RazorSemanticTokensLegend.MarkupElement); } if (ClassifyTagName((MarkupTagHelperElementSyntax)node.Parent)) { AddSemanticRange(node.Name, RazorSemanticTokensLegend.RazorTagHelperElement); } else { AddSemanticRange(node.Name, RazorSemanticTokensLegend.MarkupElement); } AddSemanticRange(node.CloseAngle, RazorSemanticTokensLegend.MarkupTagDelimiter); }
public override SyntaxNode VisitMarkupElement(MarkupElementSyntax node) { if (IsPartOfStartTag(node)) { // If this element is inside a start tag, it is some sort of malformed case like // <p @do { someattribute=\"btn\"></p>, where the end "p" tag is inside the start "p" tag. // We don't want to do tag helper parsing for this tag. return(base.VisitMarkupElement(node)); } MarkupTagHelperStartTagSyntax tagHelperStart = null; MarkupTagHelperEndTagSyntax tagHelperEnd = null; TagHelperInfo tagHelperInfo = null; // Visit the start tag. var startTag = (MarkupStartTagSyntax)Visit(node.StartTag); if (startTag != null) { var tagName = startTag.GetTagNameWithOptionalBang(); if (TryRewriteTagHelperStart(startTag, node.EndTag, out tagHelperStart, out tagHelperInfo)) { // This is a tag helper. if (tagHelperInfo.TagMode == TagMode.SelfClosing || tagHelperInfo.TagMode == TagMode.StartTagOnly) { var tagHelperElement = SyntaxFactory.MarkupTagHelperElement(tagHelperStart, body: new SyntaxList <RazorSyntaxNode>(), endTag: null); var rewrittenTagHelper = tagHelperElement.WithTagHelperInfo(tagHelperInfo); if (node.Body.Count == 0 && node.EndTag == null) { return(rewrittenTagHelper); } // This tag contains a body and/or an end tag which needs to be moved to the parent. var rewrittenNodes = SyntaxListBuilder <RazorSyntaxNode> .Create(); rewrittenNodes.Add(rewrittenTagHelper); var rewrittenBody = VisitList(node.Body); rewrittenNodes.AddRange(rewrittenBody); return(SyntaxFactory.MarkupElement(startTag: null, body: rewrittenNodes.ToList(), endTag: node.EndTag)); } else if (node.EndTag == null) { // Start tag helper with no corresponding end tag. _errorSink.OnError( RazorDiagnosticFactory.CreateParsing_TagHelperFoundMalformedTagHelper( new SourceSpan(SourceLocationTracker.Advance(startTag.GetSourceLocation(_source), "<"), tagName.Length), tagName)); } else { // Tag helper start tag. Keep track. var tracker = new TagHelperTracker(_tagHelperPrefix, tagHelperInfo); _trackerStack.Push(tracker); } } else { // Non-TagHelper tag. ValidateParentAllowsPlainStartTag(startTag); if (node.EndTag != null || (!startTag.IsSelfClosing() && !startTag.IsVoidElement())) { // Ideally we don't want to keep track of self-closing or void tags. // But if a matching end tag exists, keep track of the start tag no matter what. // We will just assume the parser had a good reason to do this. var tracker = new TagTracker(tagName, isTagHelper: false); _trackerStack.Push(tracker); } } } // Visit body between start and end tags. var body = VisitList(node.Body); // Visit end tag. var endTag = (MarkupEndTagSyntax)Visit(node.EndTag); if (endTag != null) { var tagName = endTag.GetTagNameWithOptionalBang(); if (TryRewriteTagHelperEnd(startTag, endTag, out tagHelperEnd)) { // This is a tag helper if (startTag == null) { // The end tag helper has no corresponding start tag, create an error. _errorSink.OnError( RazorDiagnosticFactory.CreateParsing_TagHelperFoundMalformedTagHelper( new SourceSpan(SourceLocationTracker.Advance(endTag.GetSourceLocation(_source), "</"), tagName.Length), tagName)); } } else { // Non tag helper end tag. if (startTag == null) { // Standalone end tag. We may need to error if it is not supposed to be here. // If there was a corresponding start tag, we would have already added this error. ValidateParentAllowsPlainEndTag(endTag); } else { // Since a start tag exists, we must already be tracking it. // Pop the stack as we're done with the end tag. _trackerStack.Pop(); } } } if (tagHelperInfo != null) { // If we get here it means this element was rewritten as a tag helper. var tagHelperElement = SyntaxFactory.MarkupTagHelperElement(tagHelperStart, body, tagHelperEnd); return(tagHelperElement.WithTagHelperInfo(tagHelperInfo)); } // There was no matching tag helper for this element. Return. return(node.Update(startTag, body, endTag)); }
private bool TryRewriteTagHelperEnd(MarkupStartTagSyntax startTag, MarkupEndTagSyntax endTag, out MarkupTagHelperEndTagSyntax rewritten) { rewritten = null; var tagName = endTag.GetTagNameWithOptionalBang(); // Could not determine tag name, it can't be a TagHelper, continue on and track the element. if (string.IsNullOrEmpty(tagName) || tagName.StartsWith("!", StringComparison.Ordinal)) { return(false); } var tracker = CurrentTagHelperTracker; var tagNameScope = tracker?.TagName ?? string.Empty; if (!IsPotentialTagHelperEnd(tagName, endTag)) { return(false); } // Validate that our end tag matches the currently scoped tag, if not we may need to error. if (startTag != null && tagNameScope.Equals(tagName, StringComparison.OrdinalIgnoreCase)) { // If there are additional end tags required before we can build our block it means we're in a // situation like this: <myth req="..."><myth></myth></myth> where we're at the inside </myth>. if (tracker.OpenMatchingTags > 0) { tracker.OpenMatchingTags--; return(false); } ValidateEndTagSyntax(tagName, endTag); _trackerStack.Pop(); } else { var tagHelperBinding = _tagHelperBinder.GetBinding( tagName, attributes: Array.Empty <KeyValuePair <string, string> >(), parentTagName: CurrentParentTagName, parentIsTagHelper: CurrentParentIsTagHelper); // If there are not TagHelperDescriptors associated with the end tag block that also have no // required attributes then it means we can't be a TagHelper, bail out. if (tagHelperBinding == null) { return(false); } foreach (var descriptor in tagHelperBinding.Descriptors) { var boundRules = tagHelperBinding.Mappings[descriptor]; var invalidRule = boundRules.FirstOrDefault(rule => rule.TagStructure == TagStructure.WithoutEndTag); if (invalidRule != null) { // End tag TagHelper that states it shouldn't have an end tag. _errorSink.OnError( RazorDiagnosticFactory.CreateParsing_TagHelperMustNotHaveAnEndTag( new SourceSpan(SourceLocationTracker.Advance(endTag.GetSourceLocation(_source), "</"), tagName.Length), tagName, descriptor.DisplayName, invalidRule.TagStructure)); return(false); } } } rewritten = SyntaxFactory.MarkupTagHelperEndTag( endTag.OpenAngle, endTag.ForwardSlash, endTag.Bang, endTag.Name, endTag.MiscAttributeContent, endTag.CloseAngle); return(true); }
public override void VisitMarkupTagHelperEndTag(MarkupTagHelperEndTagSyntax node) { WriteNode(node, isHtml: true, base.VisitMarkupTagHelperEndTag); }
public override void VisitMarkupTagHelperEndTag(MarkupTagHelperEndTagSyntax node) { // We don't want to generate a classified span for a tag helper end tag. Do nothing. }