Example #1
0
        public void WriteHtmlContent_RendersContentCorrectly()
        {
            // Arrange
            var codeWriter = new CodeWriter();
            var writer     = new RuntimeNodeWriter();
            var context    = TestCodeRenderingContext.CreateRuntime();

            var node = new HtmlContentIntermediateNode();

            node.Children.Add(new IntermediateToken()
            {
                Content = "SomeContent",
                Kind    = TokenKind.Html,
            });

            // Act
            writer.WriteHtmlContent(context, node);

            // Assert
            var csharp = context.CodeWriter.GenerateCode();

            Assert.Equal(
                @"WriteLiteral(""SomeContent"");
",
                csharp,
                ignoreLineEndingDifferences: true);
        }
Example #2
0
        public void WriteHtmlContent_LargeStringLiteral_UsesMultipleWrites()
        {
            // Arrange
            var codeWriter = new CodeWriter();
            var writer     = new RuntimeNodeWriter();
            var context    = TestCodeRenderingContext.CreateRuntime();

            var node = new HtmlContentIntermediateNode();

            node.Children.Add(new IntermediateToken()
            {
                Content = new string('*', 2000),
                Kind    = TokenKind.Html,
            });

            // Act
            writer.WriteHtmlContent(context, node);

            // Assert
            var csharp = context.CodeWriter.GenerateCode();

            Assert.Equal(string.Format(
                             @"WriteLiteral(@""{0}"");
WriteLiteral(@""{1}"");
", new string('*', 1024), new string('*', 976)),
                         csharp,
                         ignoreLineEndingDifferences: true);
        }
            public override void VisitHtml(HtmlContentIntermediateNode node)
            {
                // We need to restore the state after processing this node.
                // We might have found a leaf-block of HTML, but that shouldn't
                // affect our parent's state.
                var originalState = _foundNonHtml;

                _foundNonHtml = false;

                if (node.HasDiagnostics)
                {
                    // Treat node with errors as non-HTML
                    _foundNonHtml = true;
                }

                // Visit Children
                base.VisitDefault(node);

                if (!_foundNonHtml)
                {
                    Trees.Add(new IntermediateNodeReference(Parent, node));
                }

                _foundNonHtml = originalState |= _foundNonHtml;
            }
            public void Push(HtmlContentIntermediateNode node)
            {
                var builder = new StringBuilder();

                var offsets = new List <(int offset, int sourceOffset)>();

                if (_content != null && _position < _content.Length)
                {
                    offsets.Add((0, _offsets[0].sourceOffset + _position));
                    builder.Append(_content, _position, _content.Length - _position);
                }

                for (var i = 0; i < node.Children.Count; i++)
                {
                    var token = node.Children[i] as IntermediateToken;
                    if (token != null && token.IsHtml)
                    {
                        offsets.Add((builder.Length, token.Source.Value.AbsoluteIndex));
                        builder.Append(token.Content);
                    }
                }

                _content    = builder.ToString();
                _offsets    = offsets;
                _textSource = new TextSource(_content);
                _position   = 0;
            }
            public override void VisitHtml(HtmlContentIntermediateNode node)
            {
                if (node.Source != null)
                {
                    Items.Add(new InstrumentationItem(node, Parent, isLiteral: true, source: node.Source.Value));
                }

                VisitDefault(node);
            }
    public static void SetEncoded(this HtmlContentIntermediateNode node)
    {
        if (node == null)
        {
            throw new ArgumentNullException(nameof(node));
        }

        node.Annotations[HasEncodedContent] = HasEncodedContent;
    }
 public override void VisitHtml(HtmlContentIntermediateNode node)
 {
     for (var i = 0; i < node.Children.Count; i++)
     {
         if (node.Children[i] is IntermediateToken token)
         {
             Builder.Append(token.Content);
         }
     }
 }
Example #8
0
            public override void VisitHtml(HtmlContentIntermediateNode node)
            {
                if (node.HasDiagnostics)
                {
                    // Treat node with errors as non-HTML
                    _foundNonHtml = true;
                }

                // Visit Children
                base.VisitDefault(node);
            }
        private static string GetHtmlContent(HtmlContentIntermediateNode node)
        {
            var builder    = new StringBuilder();
            var htmlTokens = node.Children.OfType <IntermediateToken>().Where(t => t.IsHtml);

            foreach (var htmlToken in htmlTokens)
            {
                builder.Append(htmlToken.Content);
            }
            return(builder.ToString());
        }
            public override void VisitMarkupSpan(MarkupChunkGenerator chunkGenerator, Span span)
            {
                if (span.Symbols.Count == 1)
                {
                    var symbol = span.Symbols[0] as HtmlSymbol;
                    if (symbol != null &&
                        symbol.Type == HtmlSymbolType.Unknown &&
                        symbol.Content.Length == 0)
                    {
                        // We don't want to create IR nodes for marker symbols.
                        return;
                    }
                }

                var source          = BuildSourceSpanFromNode(span);
                var currentChildren = _builder.Current.Children;

                if (currentChildren.Count > 0 && currentChildren[currentChildren.Count - 1] is HtmlContentIntermediateNode)
                {
                    var existingHtmlContent = (HtmlContentIntermediateNode)currentChildren[currentChildren.Count - 1];

                    if (existingHtmlContent.Source == null && source == null)
                    {
                        Combine(existingHtmlContent, span);
                        return;
                    }

                    if (source != null &&
                        existingHtmlContent.Source != null &&
                        existingHtmlContent.Source.Value.FilePath == source.Value.FilePath &&
                        existingHtmlContent.Source.Value.AbsoluteIndex + existingHtmlContent.Source.Value.Length == source.Value.AbsoluteIndex)
                    {
                        Combine(existingHtmlContent, span);
                        return;
                    }
                }

                var contentNode = new HtmlContentIntermediateNode()
                {
                    Source = source
                };

                _builder.Push(contentNode);

                _builder.Add(new IntermediateToken()
                {
                    Content = span.Content,
                    Kind    = TokenKind.Html,
                    Source  = source,
                });

                _builder.Pop();
            }
Example #11
0
            public override void VisitTagHelperHtmlAttribute(TagHelperHtmlAttributeIntermediateNode node)
            {
                var attribute = new ComponentAttributeIntermediateNode(node);

                _children.Add(attribute);

                // Since we don't support complex content, we can rewrite the inside of this
                // node to the rather simpler form that property nodes usually have.
                for (var i = 0; i < attribute.Children.Count; i++)
                {
                    if (attribute.Children[i] is HtmlAttributeValueIntermediateNode htmlValue)
                    {
                        var newNode = new HtmlContentIntermediateNode()
                        {
                            Source = htmlValue.Source,
                        };
                        for (var j = 0; j < htmlValue.Children.Count; j++)
                        {
                            newNode.Children.Add(htmlValue.Children[j]);
                        }

                        attribute.Children[i] = newNode;
                    }
                    else if (attribute.Children[i] is CSharpExpressionAttributeValueIntermediateNode expressionValue)
                    {
                        var newNode = new CSharpExpressionIntermediateNode()
                        {
                            Source = expressionValue.Source,
                        };
                        for (var j = 0; j < expressionValue.Children.Count; j++)
                        {
                            newNode.Children.Add(expressionValue.Children[j]);
                        }

                        attribute.Children[i] = newNode;
                    }
                    else if (attribute.Children[i] is CSharpCodeAttributeValueIntermediateNode codeValue)
                    {
                        var newNode = new CSharpExpressionIntermediateNode()
                        {
                            Source = codeValue.Source,
                        };
                        for (var j = 0; j < codeValue.Children.Count; j++)
                        {
                            newNode.Children.Add(codeValue.Children[j]);
                        }

                        attribute.Children[i] = newNode;
                    }
                }
            }
Example #12
0
            private string GetContent(HtmlContentIntermediateNode node)
            {
                var builder = new StringBuilder();

                for (var i = 0; i < node.Children.Count; i++)
                {
                    if (node.Children[i] is IntermediateToken token && token.IsHtml)
                    {
                        builder.Append(token.Content);
                    }
                }

                return(builder.ToString());
            }
        private static string GetHtmlContent(HtmlContentIntermediateNode node)
        {
            var builder = new StringBuilder();

            for (var i = 0; i < node.Children.Count; i++)
            {
                var token = node.Children[i] as IntermediateToken;
                if (token != null && token.IsHtml)
                {
                    builder.Append(token.Content);
                }
            }

            return(builder.ToString());
        }
Example #14
0
        private void ProcessElement(HtmlContentIntermediateNode node, string cssScope)
        {
            // Add a minimized attribute whose name is simply the CSS scope
            for (var i = 0; i < node.Children.Count; i++)
            {
                var child = node.Children[i];
                if (child is IntermediateToken token && token.IsHtml)
                {
                    if (IsValidElement(token))
                    {
                        node.Children.Insert(i + 1, new IntermediateToken()
                        {
                            Content = cssScope,
                            Kind    = TokenKind.Html,
                            Source  = null
                        });
                        i++;
                    }
                }
            }

            bool IsValidElement(IntermediateToken token)
            {
                var content      = token.Content;
                var isValidToken = content.StartsWith("<", StringComparison.Ordinal) &&
                                   !content.StartsWith("</", StringComparison.Ordinal) &&
                                   !content.StartsWith("<!", StringComparison.Ordinal);
                /// <remarks>
                /// We want to avoid adding the CSS scope to elements that do not appear
                /// within the body element of the document. When this pass executes over the
                /// nodes, we don't have the ability to store whether we are a descandant of a
                /// `head` or `body` element so it is not possible to discern whether the tag
                /// is valid this way. Instead, we go for a straight-forward check on the tag
                /// name that we are currently inspecting.
                /// </remarks>
                var isInvalidTag = content.IndexOf("head", StringComparison.OrdinalIgnoreCase) >= 0 ||
                                   content.IndexOf("meta", StringComparison.OrdinalIgnoreCase) >= 0 ||
                                   content.IndexOf("title", StringComparison.OrdinalIgnoreCase) >= 0 ||
                                   content.IndexOf("link", StringComparison.OrdinalIgnoreCase) >= 0 ||
                                   content.IndexOf("base", StringComparison.OrdinalIgnoreCase) >= 0 ||
                                   content.IndexOf("script", StringComparison.OrdinalIgnoreCase) >= 0 ||
                                   content.IndexOf("style", StringComparison.OrdinalIgnoreCase) >= 0 ||
                                   content.IndexOf("html", StringComparison.OrdinalIgnoreCase) >= 0;

                return(isValidToken && !isInvalidTag);
            }
        }
        private static void RewriteHtmlAttributeContent(List <IntermediateNode> nodes, TagHelperHtmlAttributeIntermediateNode node)
        {
            switch (node.AttributeStructure)
            {
            case AttributeStructure.Minimized:
                nodes.Add(new HtmlContentIntermediateNode()
                {
                    Children =
                    {
                        new IntermediateToken()
                        {
                            Content = node.AttributeName + " ",
                            Kind    = TokenKind.Html,
                        }
                    }
                });
                break;

            // Blazor doesn't really care about preserving the fidelity of the attributes.
            case AttributeStructure.NoQuotes:
            case AttributeStructure.SingleQuotes:
            case AttributeStructure.DoubleQuotes:

                var htmlNode = new HtmlContentIntermediateNode();
                nodes.Add(htmlNode);

                htmlNode.Children.Add(new IntermediateToken()
                {
                    Content = node.AttributeName + "=\"",
                    Kind    = TokenKind.Html,
                });

                for (var i = 0; i < node.Children[0].Children.Count; i++)
                {
                    htmlNode.Children.Add(node.Children[0].Children[i]);
                }

                htmlNode.Children.Add(new IntermediateToken()
                {
                    Content = "\" ",
                    Kind    = TokenKind.Html,
                });

                break;
            }
        }
Example #16
0
            private void Combine(HtmlContentIntermediateNode node, SyntaxNode item)
            {
                node.Children.Add(new IntermediateToken()
                {
                    Content = item.GetContent(),
                    Kind    = TokenKind.Html,
                    Source  = BuildSourceSpanFromNode(item),
                });

                if (node.Source != null)
                {
                    Debug.Assert(node.Source.Value.FilePath != null);

                    node.Source = new SourceSpan(
                        node.Source.Value.FilePath,
                        node.Source.Value.AbsoluteIndex,
                        node.Source.Value.LineIndex,
                        node.Source.Value.CharacterIndex,
                        node.Source.Value.Length + item.FullWidth);
                }
            }
            private void Combine(HtmlContentIntermediateNode node, Span span)
            {
                node.Children.Add(new IntermediateToken()
                {
                    Content = span.Content,
                    Kind    = TokenKind.Html,
                    Source  = BuildSourceSpanFromNode(span),
                });

                if (node.Source != null)
                {
                    Debug.Assert(node.Source.Value.FilePath != null);

                    node.Source = new SourceSpan(
                        node.Source.Value.FilePath,
                        node.Source.Value.AbsoluteIndex,
                        node.Source.Value.LineIndex,
                        node.Source.Value.CharacterIndex,
                        node.Source.Value.Length + span.Content.Length);
                }
            }
Example #18
0
 private void ProcessElement(HtmlContentIntermediateNode node, string cssScope)
 {
     // Add a minimized attribute whose name is simply the CSS scope
     for (var i = 0; i < node.Children.Count; i++)
     {
         var child = node.Children[i];
         if (child is IntermediateToken token && token.IsHtml)
         {
             var content = token.Content;
             if (content.StartsWith("<", StringComparison.Ordinal) && !content.StartsWith("</", StringComparison.Ordinal))
             {
                 node.Children.Insert(i + 1, new IntermediateToken()
                 {
                     Content = cssScope,
                     Kind    = TokenKind.Html,
                     Source  = null
                 });
                 i++;
             }
         }
     }
 }
 public static bool IsEncoded(this HtmlContentIntermediateNode node)
 {
     return(ReferenceEquals(node.Annotations[HasEncodedContent], HasEncodedContent));
 }
Example #20
0
        public override void VisitHtml(HtmlContentIntermediateNode node)
        {
            for (var i = 0; i < node.Children.Count; i++)
            {
                var child = node.Children[i];
                if (!(child is IntermediateToken token) || !token.IsHtml || string.IsNullOrEmpty(token.Content))
                {
                    // We only care about Html tokens.
                    continue;
                }

                for (var j = 0; j < token.Content.Length; j++)
                {
                    var ch = token.Content[j];
                    // ASCII range is 0 - 127
                    if (ch > 127 || EncodedCharacters.Contains(ch))
                    {
                        node.SetEncoded();
                        return;
                    }
                }
            }

            // If we reach here, we don't have newlines, tabs or non-ascii characters in this node.
            // If we can successfully decode all HTML entities(if any) in this node, we can safely let it call AddContent.
            var decodedContent = new string[node.Children.Count];

            for (var i = 0; i < node.Children.Count; i++)
            {
                var child = node.Children[i];
                if (!(child is IntermediateToken token) || !token.IsHtml || string.IsNullOrEmpty(token.Content))
                {
                    // We only care about Html tokens.
                    continue;
                }

                if (TryDecodeHtmlEntities(token.Content, out var decoded))
                {
                    decodedContent[i] = decoded;
                }
                else
                {
                    node.SetEncoded();
                    return;
                }
            }

            // If we reach here, it means we have successfully decoded all content.
            // Replace all token content with the decoded value.
            for (var i = 0; i < node.Children.Count; i++)
            {
                var child = node.Children[i];
                if (!(child is IntermediateToken token) || !token.IsHtml || string.IsNullOrEmpty(token.Content))
                {
                    // We only care about Html tokens.
                    continue;
                }

                token.Content = decodedContent[i];
            }
        }
 public virtual void VisitHtml(HtmlContentIntermediateNode node)
 {
     VisitDefault(node);
 }
Example #22
0
 public override void VisitHtml(HtmlContentIntermediateNode node)
 {
     Builder.Append(Encode(node.Children));
 }
 public abstract void WriteHtmlContent(CodeRenderingContext context, HtmlContentIntermediateNode node);
Example #24
0
 public override void VisitHtml(HtmlContentIntermediateNode node)
 {
     // Visit Children
     base.VisitDefault(node);
 }
 public override void VisitHtml(HtmlContentIntermediateNode node)
 {
     Context.NodeWriter.WriteHtmlContent(Context, node);
 }
Example #26
0
            public override void VisitMarkupTextLiteral(MarkupTextLiteralSyntax node)
            {
                var context = node.GetSpanContext();

                if (context != null && context.ChunkGenerator == SpanChunkGenerator.Null)
                {
                    base.VisitMarkupTextLiteral(node);
                    return;
                }

                if (node.LiteralTokens.Count == 1)
                {
                    var token = node.LiteralTokens[0];
                    if (token != null &&
                        token.Kind == SyntaxKind.Marker &&
                        token.Content.Length == 0)
                    {
                        // We don't want to create IR nodes for marker tokens.
                        base.VisitMarkupTextLiteral(node);
                        return;
                    }
                }

                var source          = BuildSourceSpanFromNode(node);
                var currentChildren = _builder.Current.Children;

                if (currentChildren.Count > 0 && currentChildren[currentChildren.Count - 1] is HtmlContentIntermediateNode)
                {
                    var existingHtmlContent = (HtmlContentIntermediateNode)currentChildren[currentChildren.Count - 1];

                    if (existingHtmlContent.Source == null && source == null)
                    {
                        Combine(existingHtmlContent, node);
                        base.VisitMarkupTextLiteral(node);
                        return;
                    }

                    if (source != null &&
                        existingHtmlContent.Source != null &&
                        existingHtmlContent.Source.Value.FilePath == source.Value.FilePath &&
                        existingHtmlContent.Source.Value.AbsoluteIndex + existingHtmlContent.Source.Value.Length == source.Value.AbsoluteIndex)
                    {
                        Combine(existingHtmlContent, node);
                        base.VisitMarkupTextLiteral(node);
                        return;
                    }
                }

                var contentNode = new HtmlContentIntermediateNode()
                {
                    Source = source
                };

                _builder.Push(contentNode);

                _builder.Add(new IntermediateToken()
                {
                    Content = node.GetContent(),
                    Kind    = TokenKind.Html,
                    Source  = source,
                });

                _builder.Pop();

                base.VisitMarkupTextLiteral(node);
            }