| File: Language\TagHelpers\Producers\AcceptsAssetPathTagHelperProducer.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.Collections.Immutable; using System.Threading; using Microsoft.AspNetCore.Razor.Language.Components; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor; namespace Microsoft.AspNetCore.Razor.Language.TagHelpers.Producers; // Reads the runtime's [AcceptsAssetPath(elementName, attributeName)] declarations and produces a // carrier TagHelperDescriptor per element/attribute pair. These descriptors never match an // element (they declare no tag-matching rules); they exist purely so ComponentTildePathPass // can discover which element/attribute combinations opt into '~/' asset-path expansion. The // declarations live on a public convention type named AssetPathAttributes. internal sealed partial class AcceptsAssetPathTagHelperProducer : TagHelperProducer { private readonly INamedTypeSymbol _acceptsAssetPathAttributeType; private AcceptsAssetPathTagHelperProducer(INamedTypeSymbol acceptsAssetPathAttributeType) { _acceptsAssetPathAttributeType = acceptsAssetPathAttributeType; } public override TagHelperProducerKind Kind => TagHelperProducerKind.AcceptsAssetPath; public override bool SupportsTypes => true; public override bool IsCandidateType(INamedTypeSymbol type) => type.DeclaredAccessibility == Accessibility.Public && type.Name == ComponentsApi.AcceptsAssetPathAttribute.CandidateTypeName; public override void AddTagHelpersForType( INamedTypeSymbol type, ref TagHelperCollection.RefBuilder results, CancellationToken cancellationToken) { var typeName = type.GetDefaultDisplayString(); var namespaceName = type.ContainingNamespace.GetFullName(); foreach (var attribute in type.GetAttributes()) { if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, _acceptsAssetPathAttributeType) && TryGetArgs(attribute, out var element, out var attributeName)) { results.Add(CreateTagHelper(typeName, namespaceName, type.Name, element, attributeName)); } } } private static bool TryGetArgs(AttributeData attribute, out string element, out string attributeName) { // AcceptsAssetPathAttribute(string element, string attribute) if (attribute.ConstructorArguments is [ { Value: string elementValue }, { Value: string attributeValue }]) { element = elementValue; attributeName = attributeValue; return true; } element = null!; attributeName = null!; return false; } private static TagHelperDescriptor CreateTagHelper( string typeName, string typeNamespace, string typeNameIdentifier, string element, string attribute) { using var _ = TagHelperDescriptorBuilder.GetPooledInstance( TagHelperKind.AssetPath, $"{element}[{attribute}]", ComponentsApi.AssemblyName, out var builder); builder.SetTypeName(typeName, typeNamespace, typeNameIdentifier); builder.CaseSensitive = true; builder.SetMetadata(new AssetPathMetadata() { Element = element, Attribute = attribute, }); return builder.Build(); } }