| File: Language\Syntax\SyntaxUtilities.cs | Web Access |
| Project: src\roslyn\src\Razor\src\Compiler\Microsoft.CodeAnalysis.Razor.Compiler\src\Microsoft.CodeAnalysis.Razor.Compiler.csproj (Microsoft.CodeAnalysis.Razor.Compiler) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using Microsoft.AspNetCore.Razor.Language.Legacy; using Microsoft.AspNetCore.Razor.PooledObjects; namespace Microsoft.AspNetCore.Razor.Language.Syntax; internal static class SyntaxUtilities { internal static SyntaxList<RazorSyntaxNode> GetRewrittenMarkupStartTagChildren( MarkupStartTagSyntax node, bool includeEditHandler = false) { // Rewrites the children of the start tag to look like the legacy syntax tree. if (node.IsMarkupTransition) { return GetRewrittenMarkupNodeChildren(node, node.ChunkGenerator, includeEditHandler); } using PooledArrayBuilder<RazorSyntaxNode> newChildren = []; using PooledArrayBuilder<MarkupTextLiteralSyntax> literals = []; SpanEditHandler? latestEditHandler = null; foreach (var child in node.LegacyChildren) { switch (child) { case MarkupTextLiteralSyntax literal: literals.Add(literal); if (includeEditHandler) { latestEditHandler = literal.EditHandler ?? latestEditHandler; } break; case MarkupMiscAttributeContentSyntax miscContent: foreach (var contentChild in miscContent.Children) { if (contentChild is MarkupTextLiteralSyntax contentLiteral) { literals.Add(contentLiteral); if (includeEditHandler) { latestEditHandler = contentLiteral.EditHandler ?? latestEditHandler; } } else { // Pop stack AddLiteralIsIfNeeded(); newChildren.Add(contentChild); } } break; default: AddLiteralIsIfNeeded(); newChildren.Add(child); break; } } AddLiteralIsIfNeeded(); return newChildren.ToList(node); void AddLiteralIsIfNeeded() { if (literals.Count > 0) { var mergedLiteral = MergeTextLiterals(literals.ToArrayAndClear(), includeEditHandler ? latestEditHandler : null); latestEditHandler = null; newChildren.Add(mergedLiteral); } } } private static MarkupTextLiteralSyntax MergeTextLiterals(ReadOnlySpan<MarkupTextLiteralSyntax?> literals, SpanEditHandler? editHandler) { SyntaxNode? parent = null; var position = 0; var seenFirstLiteral = false; using PooledArrayBuilder<SyntaxToken> builder = []; foreach (var literal in literals) { if (literal == null) { continue; } if (!seenFirstLiteral) { // Set the parent and position of the merged literal to the value of the first non-null literal. parent = literal.Parent; position = literal.Position; seenFirstLiteral = true; } builder.AddRange(literal.LiteralTokens); } return (MarkupTextLiteralSyntax)InternalSyntax.SyntaxFactory .MarkupTextLiteral( literalTokens: builder.ToGreenListNode().ToGreenList<InternalSyntax.SyntaxToken>(), chunkGenerator: null, editHandler: editHandler) .CreateRed(parent, position); } internal static SyntaxList<RazorSyntaxNode> GetRewrittenMarkupEndTagChildren( MarkupEndTagSyntax node, bool includeEditHandler = false) { // Rewrites the children of the end tag to look like the legacy syntax tree. return node.IsMarkupTransition ? GetRewrittenMarkupNodeChildren(node, node.ChunkGenerator, includeEditHandler) : node.LegacyChildren; } internal static SyntaxList<RazorSyntaxNode> GetRewrittenMarkupNodeChildren( MarkupSyntaxNode node, ISpanChunkGenerator chunkGenerator, bool includeEditHandler = false) { using PooledArrayBuilder<SyntaxToken> builder = []; foreach (var token in node.DescendantTokens()) { if (!token.IsMissing) { builder.Add(token); } } var markupTransition = InternalSyntax.SyntaxFactory .MarkupTransition( builder.ToGreenListNode().ToGreenList<InternalSyntax.SyntaxToken>(), chunkGenerator, includeEditHandler ? node.GetEditHandler() : null) .CreateRed(node, node.Position); return new(markupTransition); } }