public override void VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax node)
        {
            var isComponent = IsComponentTagHelperNode(node);

            Visit(node.StartTag);

            _currentHtmlIndentationLevel++;
            if (isComponent)
            {
                _componentTracker.Push(node);
            }

            foreach (var child in node.Body)
            {
                Visit(child);
            }

            if (isComponent)
            {
                Debug.Assert(_componentTracker.Any(), "Component tracker should not be empty.");
                _componentTracker.Pop();
            }
            _currentHtmlIndentationLevel--;

            Visit(node.EndTag);

            bool IsComponentTagHelperNode(MarkupTagHelperElementSyntax node)
            {
                return(node.TagHelperInfo?.BindingResult?.Descriptors?.Any(
                           d => d.IsComponentOrChildContentTagHelper()) ?? false);
            }
        }
Exemplo n.º 2
0
            static bool ParentHasProperty(MarkupTagHelperElementSyntax parentComponent, string?propertyName)
            {
                // If this is a child tag helper that match a property of its parent tag helper
                // then it means this specific node won't actually cause a change in indentation.
                // For example, the following two bits of Razor generate identical C# code, even though the code block is
                // nested in a different number of tag helper elements:
                //
                // <Component>
                //     @if (true)
                //     {
                //     }
                // </Component>
                //
                // and
                //
                // <Component>
                //     <ChildContent>
                //         @if (true)
                //         {
                //         }
                //     </ChildContent>
                // </Component>
                //
                // This code will not count "ChildContent" as causing indentation because its parent
                // has a property called "ChildContent".
                if (parentComponent.TagHelperInfo?.BindingResult.Descriptors.Any(d => d.BoundAttributes.Any(a => a.Name == propertyName)) ?? false)
                {
                    return(true);
                }

                return(false);
            }
        public override void VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax node)
        {
            var isComponent = IsComponentTagHelperNode(node);

            Visit(node.StartTag);

            _currentHtmlIndentationLevel++;
            if (isComponent)
            {
                _componentTracker.Push(node);
            }

            foreach (var child in node.Body)
            {
                Visit(child);
            }

            if (isComponent)
            {
                Debug.Assert(_componentTracker.Any(), "Component tracker should not be empty.");
                _componentTracker.Pop();
            }
            _currentHtmlIndentationLevel--;

            Visit(node.EndTag);
Exemplo n.º 4
0
        public override void VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax node)
        {
            var span = new TagHelperSpanInternal(node.GetSourceSpan(_source), node.TagHelperInfo.BindingResult);

            _spans.Add(span);

            base.VisitMarkupTagHelperElement(node);
        }
Exemplo n.º 5
0
 public override void VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax node)
 {
     Visit(node.StartTag);
     _currentIndentationLevel++;
     foreach (var child in node.Body)
     {
         Visit(child);
     }
     _currentIndentationLevel--;
     Visit(node.EndTag);
 }
        // We don't want to classify TagNames of well-known HTML
        // elements as TagHelpers (even if they are). So the 'input' in`<input @onclick='...' />`
        // needs to not be marked as a TagHelper, but `<Input @onclick='...' />` should be.
        private static bool ClassifyTagName(MarkupTagHelperElementSyntax node)
        {
            if (node is null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            if (node.StartTag != null && node.StartTag.Name != null)
            {
                var binding = node.TagHelperInfo.BindingResult;
                return(!binding.IsAttributeMatch);
            }

            return(false);
        }
Exemplo n.º 7
0
        private void WriteTagHelperElement(MarkupTagHelperElementSyntax node)
        {
            // Write tag name
            WriteSeparator();
            Write($"{node.TagHelperInfo.TagName}[{node.TagHelperInfo.TagMode}]");

            // Write descriptors
            foreach (var descriptor in node.TagHelperInfo.BindingResult.Descriptors)
            {
                WriteSeparator();

                // Get the type name without the namespace.
                var typeName = descriptor.Name.Substring(descriptor.Name.LastIndexOf('.') + 1);
                Write(typeName);
            }
        }
Exemplo n.º 8
0
        private static void WriteTagHelperElement(MarkupTagHelperElementSyntax node, StringBuilder builder)
        {
            // Write tag name
            builder.Append(" - ");
            builder.Append($"{node.TagHelperInfo.TagName}[{node.TagHelperInfo.TagMode}]");

            // Write descriptors
            foreach (var descriptor in node.TagHelperInfo.BindingResult.Descriptors)
            {
                builder.Append(" - ");

                // Get the type name without the namespace.
                var typeName = descriptor.Name.Substring(descriptor.Name.LastIndexOf('.') + 1);
                builder.Append(typeName);
            }
        }
Exemplo n.º 9
0
            static bool HasUnspecifiedCascadingTypeParameter(MarkupTagHelperElementSyntax node)
            {
                var tagHelperInfo = node.TagHelperInfo;

                if (tagHelperInfo is null)
                {
                    return(false);
                }

                var descriptors = tagHelperInfo.BindingResult?.Descriptors;

                if (descriptors is null)
                {
                    return(false);
                }

                // A cascading type parameter will mean the generated code will get a TypeInference class generated
                // for it, which we need to account for with an extra level of indentation in our expected C# indentation
                var hasCascadingGenericParameters = descriptors.Any(d => d.SuppliesCascadingGenericParameters());

                if (!hasCascadingGenericParameters)
                {
                    return(false);
                }

                // BUT, because life wasn't mean to be easy, the indentation is only affected when the developer
                // doesn't specify any type parameter in the element itself as an attribute.

                // Get all type parameters for later use. Array is fine to use as the list should be tiny (I hope!!)
                var typeParameterNames = descriptors.SelectMany(d => d.GetTypeParameters().Select(p => p.Name)).ToArray();

                var attributes = node.StartTag.Attributes.OfType <MarkupTagHelperAttributeSyntax>();

                foreach (var attribute in attributes)
                {
                    if (attribute.TagHelperAttributeInfo.Bound)
                    {
                        var name = attribute.TagHelperAttributeInfo.Name;
                        if (typeParameterNames.Contains(name))
                        {
                            return(false);
                        }
                    }
                }

                return(true);
            }
Exemplo n.º 10
0
            static bool DoesComponentHaveCascadingTypeParameter(MarkupTagHelperElementSyntax node)
            {
                var tagHelperInfo = node.TagHelperInfo;

                if (tagHelperInfo is null)
                {
                    return(false);
                }

                var descriptors = tagHelperInfo.BindingResult?.Descriptors;

                if (descriptors is null)
                {
                    return(false);
                }

                return(descriptors.Any(d => d.SuppliesCascadingGenericParameters()));
            }
Exemplo n.º 11
0
            static bool IsComponentTagHelperNode(MarkupTagHelperElementSyntax node)
            {
                var tagHelperInfo = node.TagHelperInfo;

                if (tagHelperInfo is null)
                {
                    return(false);
                }

                var descriptors = tagHelperInfo.BindingResult?.Descriptors;

                if (descriptors is null)
                {
                    return(false);
                }

                return(descriptors.Any(d => d.IsComponentOrChildContentTagHelper()));
            }
Exemplo n.º 12
0
            public override void VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax node)
            {
                var info    = node.TagHelperInfo;
                var tagName = info.TagName;

                if (_tagHelperPrefix != null)
                {
                    tagName = tagName.Substring(_tagHelperPrefix.Length);
                }

                var tagHelperNode = new TagHelperIntermediateNode()
                {
                    TagName = tagName,
                    TagMode = info.TagMode,
                    Source  = BuildSourceSpanFromNode(node)
                };

                foreach (var tagHelper in info.BindingResult.Descriptors)
                {
                    tagHelperNode.TagHelpers.Add(tagHelper);
                }

                _builder.Push(tagHelperNode);

                _builder.Push(new TagHelperBodyIntermediateNode());

                foreach (var item in node.Body)
                {
                    Visit(item);
                }

                _builder.Pop(); // Pop InitializeTagHelperStructureIntermediateNode

                Visit(node.StartTag);

                _builder.Pop(); // Pop TagHelperIntermediateNode

                // No need to visit the end tag because we don't write any IR for it.

                // We don't want to track attributes from a previous tag helper element.
                _renderedBoundAttributeNames.Clear();
            }
        public List <TextEdit> CreateEditsForMarkupTagHelperElement(MarkupTagHelperElementSyntax element, RazorCodeDocument codeDocument, string newName)
        {
            var edits = new List <TextEdit>
            {
                new TextEdit()
                {
                    Range   = element.StartTag.Name.GetRange(codeDocument.Source),
                    NewText = newName,
                },
            };

            if (element.EndTag != null)
            {
                edits.Add(new TextEdit()
                {
                    Range   = element.EndTag.Name.GetRange(codeDocument.Source),
                    NewText = newName,
                });
            }
            return(edits);
        }
Exemplo n.º 14
0
        // We don't want to classify TagNames of well-known HTML
        // elements as TagHelpers (even if they are). So the 'input' in`<input @onclick='...' />`
        // needs to not be marked as a TagHelper, but `<Input @onclick='...' />` should be.
        private bool ClassifyTagName(MarkupTagHelperElementSyntax node)
        {
            if (node is null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            if (node.StartTag != null && node.StartTag.Name != null)
            {
                var name = node.StartTag.Name.Content;

                if (!HtmlFactsService.IsHtmlTagName(name))
                {
                    // We always classify non-HTML tag names as TagHelpers if they're within a MarkupTagHelperElementSyntax
                    return(true);
                }

                // This must be a well-known HTML tag name like 'input', 'br'.

                var binding = node.TagHelperInfo.BindingResult;
                foreach (var descriptor in binding.Descriptors)
                {
                    if (!descriptor.IsComponentTagHelper())
                    {
                        return(false);
                    }
                }

                if (name.Length > 0 && char.IsUpper(name[0]))
                {
                    // pascal cased Component TagHelper tag name such as <Input>
                    return(true);
                }
            }

            return(false);
        }
Exemplo n.º 15
0
        public override void VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax node)
        {
            var isComponent = IsComponentTagHelperNode(node);
            // Components with cascading type parameters cause an extra level of indentation
            var componentIndentationLevels = isComponent && HasUnspecifiedCascadingTypeParameter(node) ? 2 : 1;

            var causesIndentation = isComponent;

            if (node.Parent is MarkupTagHelperElementSyntax parentComponent &&
                IsComponentTagHelperNode(parentComponent) &&
                ParentHasProperty(parentComponent, node.TagHelperInfo?.TagName))
            {
                causesIndentation = false;
            }

            Visit(node.StartTag);

            _currentHtmlIndentationLevel++;
            if (causesIndentation)
            {
                _currentComponentIndentationLevel += componentIndentationLevels;
            }

            foreach (var child in node.Body)
            {
                Visit(child);
            }

            if (causesIndentation)
            {
                Debug.Assert(_currentComponentIndentationLevel > 0, "Component indentation level should not be at 0.");
                _currentComponentIndentationLevel -= componentIndentationLevels;
            }

            _currentHtmlIndentationLevel--;

            Visit(node.EndTag);
Exemplo n.º 16
0
 public override void VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax node)
 {
     WriteBlock(node, BlockKindInternal.Tag, base.VisitMarkupTagHelperElement);
 }
 static bool IsComponentTagHelperNode(MarkupTagHelperElementSyntax node)
 {
     return(node.TagHelperInfo?.BindingResult?.Descriptors?.Any(
                d => d.IsComponentOrChildContentTagHelper()) ?? false);
 }