Ejemplo n.º 1
0
            private SyntaxNode RewriteNode(SyntaxNode node)
            {
                if (node.IsToken)
                {
                    // Tokens don't have children.
                    return(node);
                }

                _startTagTracker.Clear();
                var children          = node.ChildNodes().ToList();
                var rewrittenChildren = new List <SyntaxNode>(children.Count);

                for (var i = 0; i < children.Count; i++)
                {
                    var child = children[i];
                    if (!(child is MarkupTagBlockSyntax tagBlock))
                    {
                        TrackChild(child, rewrittenChildren);
                        continue;
                    }

                    var tagName = tagBlock.GetTagName();
                    if (string.IsNullOrWhiteSpace(tagName) || tagBlock.IsSelfClosing())
                    {
                        // Don't want to track incomplete, invalid (Eg. </>, <  >), void or self-closing tags.
                        // Simply wrap it in a block with no body or start/end tag.
                        if (IsEndTag(tagBlock))
                        {
                            // This is an error case.
                            BuildMarkupElement(rewrittenChildren, startTag: null, tagChildren: new List <RazorSyntaxNode>(), endTag: tagBlock);
                        }
                        else
                        {
                            BuildMarkupElement(rewrittenChildren, startTag: tagBlock, tagChildren: new List <RazorSyntaxNode>(), endTag: null);
                        }
                    }
                    else if (IsEndTag(tagBlock))
                    {
                        if (string.Equals(CurrentStartTagName, tagName, StringComparison.OrdinalIgnoreCase))
                        {
                            var startTagTracker = _startTagTracker.Pop();
                            var startTag        = startTagTracker.TagBlock;

                            // Get the nodes between the start and the end tag.
                            var tagChildren = startTagTracker.Children;

                            BuildMarkupElement(rewrittenChildren, startTag, tagChildren, endTag: tagBlock);
                        }
                        else
                        {
                            // Current tag scope does not match the end tag. Attempt to recover the start tag
                            // by looking up the previous tag scopes for a matching start tag.
                            if (!TryRecoverStartTag(rewrittenChildren, tagName, tagBlock))
                            {
                                // Could not recover. The end tag doesn't have a corresponding start tag. Wrap it in a block and move on.
                                var rewritten = SyntaxFactory.MarkupElement(startTag: null, body: new SyntaxList <RazorSyntaxNode>(), endTag: tagBlock);
                                TrackChild(rewritten, rewrittenChildren);
                            }
                        }
                    }
                    else
                    {
                        // This is a start tag. Keep track of it.
                        _startTagTracker.Push(new TagBlockTracker(tagBlock));
                    }
                }

                while (_startTagTracker.Count > 0)
                {
                    // We reached the end of the list and still have unmatched start tags
                    var startTagTracker = _startTagTracker.Pop();
                    var startTag        = startTagTracker.TagBlock;
                    var tagChildren     = startTagTracker.Children;
                    BuildMarkupElement(rewrittenChildren, startTag, tagChildren, endTag: null);
                }

                // We now have finished building our list of rewritten Children.
                // At this point, We should have a one to one replacement for every child. The replacement can be null.
                Debug.Assert(children.Count == rewrittenChildren.Count);
                node = node.ReplaceNodes(children, (original, rewritten) =>
                {
                    var originalIndex = children.IndexOf(original);
                    if (originalIndex != -1)
                    {
                        // If this returns null, that node will be removed.
                        return(rewrittenChildren[originalIndex]);
                    }

                    return(original);
                });

                return(node);
            }