File: Utilities\AIJsonSchemaCreateContext.cs
Web Access
Project: src\src\Libraries\Microsoft.Extensions.AI.Abstractions\Microsoft.Extensions.AI.Abstractions.csproj (Microsoft.Extensions.AI.Abstractions)
// 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 System.Linq;
using System.Reflection;
using System.Text.Json.Schema;
using System.Text.Json.Serialization.Metadata;
 
#pragma warning disable CA1815 // Override equals and operator equals on value types
 
namespace Microsoft.Extensions.AI;
 
/// <summary>
/// Defines the context in which a JSON schema within a type graph is being generated.
/// </summary>
/// <remarks>
/// This struct is being passed to the user-provided <see cref="AIJsonSchemaCreateOptions.TransformSchemaNode"/> 
/// callback by the <see cref="AIJsonUtilities.CreateJsonSchema"/> method and cannot be instantiated directly.
/// </remarks>
public readonly struct AIJsonSchemaCreateContext
{
    private readonly JsonSchemaExporterContext _exporterContext;
 
    internal AIJsonSchemaCreateContext(JsonSchemaExporterContext exporterContext)
    {
        _exporterContext = exporterContext;
    }
 
    /// <summary>
    /// Gets the path to the schema document currently being generated.
    /// </summary>
    public ReadOnlySpan<string> Path => _exporterContext.Path;
 
    /// <summary>
    /// Gets the <see cref="JsonTypeInfo"/> for the type being processed.
    /// </summary>
    public JsonTypeInfo TypeInfo => _exporterContext.TypeInfo;
 
    /// <summary>
    /// Gets the type info for the polymorphic base type if generated as a derived type.
    /// </summary>
    public JsonTypeInfo? BaseTypeInfo => _exporterContext.BaseTypeInfo;
 
    /// <summary>
    /// Gets the <see cref="JsonPropertyInfo"/> if the schema is being generated for a property.
    /// </summary>
    public JsonPropertyInfo? PropertyInfo => _exporterContext.PropertyInfo;
 
    /// <summary>
    /// Gets the declaring type of the property or parameter being processed.
    /// </summary>
    public Type? DeclaringType =>
#if NET9_0_OR_GREATER
        _exporterContext.PropertyInfo?.DeclaringType;
#else
        _exporterContext.DeclaringType;
#endif
 
    /// <summary>
    /// Gets the <see cref="ICustomAttributeProvider"/> corresponding to the property or field being processed.
    /// </summary>
    public ICustomAttributeProvider? PropertyAttributeProvider =>
#if NET9_0_OR_GREATER
        _exporterContext.PropertyInfo?.AttributeProvider;
#else
        _exporterContext.PropertyAttributeProvider;
#endif
 
    /// <summary>
    /// Gets the <see cref="System.Reflection.ICustomAttributeProvider"/> of the
    /// constructor parameter associated with the accompanying <see cref="PropertyInfo"/>.
    /// </summary>
    public ICustomAttributeProvider? ParameterAttributeProvider =>
#if NET9_0_OR_GREATER
        _exporterContext.PropertyInfo?.AssociatedParameter?.AttributeProvider;
#else
        _exporterContext.ParameterInfo;
#endif
 
    /// <summary>
    /// Retrieves a custom attribute of a specified type that is applied to the specified schema node context.
    /// </summary>
    /// <typeparam name="TAttribute">The type of attribute to search for.</typeparam>
    /// <param name="inherit">If <see langword="true"/>, specifies to also search the ancestors of the context members for custom attributes.</param>
    /// <returns>The first occurrence of <typeparamref name="TAttribute"/> if found, or <see langword="null"/> otherwise.</returns>
    /// <remarks>
    /// This helper method resolves attributes from context locations in the following order:
    /// <list type="number">
    /// <item>Attributes specified on the property of the context, if specified.</item>
    /// <item>Attributes specified on the constructor parameter of the context, if specified.</item>
    /// <item>Attributes specified on the type of the context.</item>
    /// </list>
    /// </remarks>
    public TAttribute? GetCustomAttribute<TAttribute>(bool inherit = false)
        where TAttribute : Attribute
    {
        return GetCustomAttr(PropertyAttributeProvider) ??
            GetCustomAttr(ParameterAttributeProvider) ??
            GetCustomAttr(TypeInfo.Type);
 
        TAttribute? GetCustomAttr(ICustomAttributeProvider? provider) =>
            (TAttribute?)provider?.GetCustomAttributes(typeof(TAttribute), inherit).FirstOrDefault();
    }
}