File: Documentation\DocumentationCacheKey.cs
Web Access
Project: src\src\Aspire.Cli\Aspire.Cli.csproj (aspire)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
namespace Aspire.Cli.Documentation;
 
/// <summary>
/// Builds user-friendly cache keys from documentation source URLs.
/// </summary>
internal static class DocumentationCacheKey
{
    private const string DefaultAspireHost = "aspire.dev";
 
    /// <summary>
    /// Creates a friendly cache key from the specified URL.
    /// </summary>
    /// <param name="url">The source URL to convert.</param>
    /// <param name="fallbackStem">The fallback stem to use when the URL has no usable path segments.</param>
    /// <returns>A cache key that omits the default Aspire host while preserving configured-host separation.</returns>
    public static string FromUrl(string url, string fallbackStem)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(url);
        ArgumentException.ThrowIfNullOrWhiteSpace(fallbackStem);
 
        var trimmedUrl = url.Trim();
        if (!Uri.TryCreate(trimmedUrl, UriKind.Absolute, out var uri))
        {
            var fallback = Path.GetFileNameWithoutExtension(trimmedUrl);
            return string.IsNullOrWhiteSpace(fallback) ? fallbackStem : fallback;
        }
 
        var rawSegments = uri.AbsolutePath.Split('/', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        var pathSegments = new List<string>(rawSegments.Length);
        for (var i = 0; i < rawSegments.Length; i++)
        {
            var segment = i == rawSegments.Length - 1
                ? Path.GetFileNameWithoutExtension(rawSegments[i])
                : rawSegments[i];
 
            if (!string.IsNullOrWhiteSpace(segment))
            {
                pathSegments.Add(segment);
            }
        }
 
        var stem = pathSegments.Count > 0 ? string.Join('-', pathSegments) : fallbackStem;
        if (uri.Host.Equals(DefaultAspireHost, StringComparison.OrdinalIgnoreCase) && uri.IsDefaultPort)
        {
            return stem;
        }
 
        return $"{uri.Host}{(uri.IsDefaultPort ? "" : $"-{uri.Port}")}-{stem}";
    }
}