File: Language\TagMatchingRuleDescriptor.cs
Web Access
Project: src\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.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.AspNetCore.Razor.Utilities;
using Microsoft.CodeAnalysis;
 
namespace Microsoft.AspNetCore.Razor.Language;
 
[DebuggerDisplay($"{{{nameof(GetDebuggerDisplay)}(),nq}}")]
public sealed class TagMatchingRuleDescriptor : TagHelperObject<TagMatchingRuleDescriptor>
{
    private TagHelperDescriptor? _parent;
 
    public string TagName { get; }
    public string? ParentTag { get; }
    public TagStructure TagStructure { get; }
    public bool CaseSensitive { get; }
    public ImmutableArray<RequiredAttributeDescriptor> Attributes { get; }
 
    internal TagMatchingRuleDescriptor(
        string tagName,
        string? parentTag,
        TagStructure tagStructure,
        bool caseSensitive,
        ImmutableArray<RequiredAttributeDescriptor> attributes,
        ImmutableArray<RazorDiagnostic> diagnostics)
        : base(diagnostics)
    {
        TagName = tagName;
        ParentTag = parentTag;
        TagStructure = tagStructure;
        CaseSensitive = caseSensitive;
        Attributes = attributes.NullToEmpty();
 
        foreach (var attribute in Attributes)
        {
            attribute.SetParent(this);
        }
    }
 
    private protected override void BuildChecksum(in Checksum.Builder builder)
    {
        builder.Append(TagName);
        builder.Append(ParentTag);
        builder.Append((int)TagStructure);
 
        builder.Append(CaseSensitive);
 
        foreach (var descriptor in Attributes)
        {
            builder.Append(descriptor.Checksum);
        }
    }
 
    public TagHelperDescriptor Parent
        => _parent ?? ThrowHelper.ThrowInvalidOperationException<TagHelperDescriptor>(Resources.Parent_has_not_been_set);
 
    internal void SetParent(TagHelperDescriptor parent)
    {
        Debug.Assert(parent != null);
        Debug.Assert(_parent == null);
 
        _parent = parent;
    }
 
    public IEnumerable<RazorDiagnostic> GetAllDiagnostics()
    {
        foreach (var attribute in Attributes)
        {
            foreach (var diagnostic in attribute.Diagnostics)
            {
                yield return diagnostic;
            }
        }
 
        foreach (var diagnostic in Diagnostics)
        {
            yield return diagnostic;
        }
    }
 
    internal string GetDebuggerDisplay()
    {
        var tagName = TagName ?? "*";
        tagName += TagStructure == TagStructure.WithoutEndTag ? "/" : "";
        return $"{TagName ?? "*"}[{string.Join(", ", Attributes.Select(a => DescribeAttribute(a)))}]";
        static string DescribeAttribute(RequiredAttributeDescriptor attribute)
        {
            var name = attribute.Name switch
            {
                null => "*",
                var prefix when attribute.NameComparison == RequiredAttributeNameComparison.PrefixMatch => $"^{prefix}",
                var full => full,
            };
 
            var value = attribute.Value switch
            {
                null => "",
                var prefix when attribute.ValueComparison == RequiredAttributeValueComparison.PrefixMatch => $"^={prefix}",
                var suffix when attribute.ValueComparison == RequiredAttributeValueComparison.SuffixMatch => $"$={suffix}",
                var full => $"={full}",
            };
            return name + value;
        }
    }
}