private static SyntaxNode?GetStartOrEndTagName(SyntaxNode node)
 {
     return(node switch
     {
         MarkupTagHelperStartTagSyntax tagHelperStartTag => tagHelperStartTag.Name,
         MarkupTagHelperEndTagSyntax tagHelperEndTag => tagHelperEndTag.Name,
         _ => null
     });
Example #2
0
 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);
 }
Example #4
0
 public override void VisitMarkupTagHelperEndTag(MarkupTagHelperEndTagSyntax node)
 {
     WriteBlock(node, FormattingBlockKind.Tag, n =>
     {
         foreach (var child in n.Children)
         {
             Visit(child);
         }
     });
 }
Example #5
0
        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);
        }
Example #6
0
        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);
        }
Example #7
0
            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));
            }
Example #8
0
            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);
            }
Example #9
0
 public override void VisitMarkupTagHelperEndTag(MarkupTagHelperEndTagSyntax node)
 {
     WriteNode(node, isHtml: true, base.VisitMarkupTagHelperEndTag);
 }
Example #10
0
 public override void VisitMarkupTagHelperEndTag(MarkupTagHelperEndTagSyntax node)
 {
     // We don't want to generate a classified span for a tag helper end tag. Do nothing.
 }