File: ConsoleLogs\UrlParser.cs
Web Access
Project: src\src\Aspire.Dashboard\Aspire.Dashboard.csproj (Aspire.Dashboard)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
 
namespace Aspire.Dashboard.ConsoleLogs;
 
public static partial class UrlParser
{
    private static readonly Regex s_urlRegEx = GenerateUrlRegEx();
 
    public static bool TryParse(string? text, Func<string, string>? nonMatchFragmentCallback, [NotNullWhen(true)] out string? modifiedText)
    {
        if (text is not null)
        {
            var urlMatch = s_urlRegEx.Match(text);
 
            StringBuilder? builder = null;
 
            var nextCharIndex = 0;
            while (urlMatch.Success)
            {
                builder ??= new StringBuilder(text.Length * 2);
 
                if (urlMatch.Index > 0)
                {
                    AppendNonMatchFragment(builder, nonMatchFragmentCallback, text[(nextCharIndex)..urlMatch.Index]);
                }
 
                var urlStart = urlMatch.Index;
                nextCharIndex = urlMatch.Index + urlMatch.Length;
                var url = text[urlStart..nextCharIndex];
 
                builder.Append(CultureInfo.InvariantCulture, $"<a target=\"_blank\" href=\"{url}\">{WebUtility.HtmlEncode(url)}</a>");
                urlMatch = urlMatch.NextMatch();
            }
 
            if (builder?.Length > 0)
            {
                if (nextCharIndex < text.Length)
                {
                    AppendNonMatchFragment(builder, nonMatchFragmentCallback, text[(nextCharIndex)..]);
                }
 
                modifiedText = builder.ToString();
                return true;
            }
        }
 
        modifiedText = null;
        return false;
 
        static void AppendNonMatchFragment(StringBuilder stringBuilder, Func<string, string>? nonMatchFragmentCallback, string text)
        {
            if (nonMatchFragmentCallback != null)
            {
                text = nonMatchFragmentCallback(text);
            }
 
            stringBuilder.Append(text);
        }
    }
 
    // Regular expression that detects http/https URLs in a log entry
    // Based on the RegEx used by GitHub to detect links in content.
    [GeneratedRegex(
        @"((?<!\+)https?:\/\/(?:www\.)?(?:[-\p{L}.]+?[.@][a-zA-Z\d]{2,}|localhost)(?:[-\w\p{L}.:%+~#*$!?&/=@]*(?:,(?!\s))*?)*)",
        RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture)]
    public static partial Regex GenerateUrlRegEx();
}