From e14e8466d005717d4c8caeca02b57f8590c654d0 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Tue, 6 Oct 2026 08:47:18 -0400 Subject: [PATCH 1/2] Repair XREF Generator tool --- .../Pages/Home.razor | 94 ++++++++++++++++--- 1 file changed, 82 insertions(+), 12 deletions(-) diff --git a/BlazorWebAssemblyXrefGenerator/Pages/Home.razor b/BlazorWebAssemblyXrefGenerator/Pages/Home.razor index 6eff6e136..e760bf19b 100644 --- a/BlazorWebAssemblyXrefGenerator/Pages/Home.razor +++ b/BlazorWebAssemblyXrefGenerator/Pages/Home.razor @@ -1,5 +1,6 @@ @page "/" @using System.Net +@using System.Text @using System.Text.RegularExpressions @inject IHttpClientFactory ClientFactory @@ -83,6 +84,7 @@ message = string.Empty; var apiClient = ClientFactory.CreateClient("APIClient"); + if (string.IsNullOrEmpty(Model?.SearchText) || apiClient == null) { isSearching = false; @@ -91,26 +93,32 @@ try { - SearchResultItems = await apiClient.GetFromJsonAsync($"api/apibrowser/dotnet/search?api-version=0.2&search={Model.SearchText}"); + SearchResultItems = await apiClient.GetFromJsonAsync($"api/apibrowser/dotnet/search?search={Model.SearchText}"); if (SearchResultItems?.Results?.Any() == true) { - var index = 1; foreach (var result in SearchResultItems.Results.Take(MaxResults)) { - var client = ClientFactory.CreateClient(); - var encodedUrl = WebUtility.UrlEncode($"https://learn.microsoft.com/en-us{result.Url}?view={dotNetVersion}"); - using var request = new HttpRequestMessage(HttpMethod.Get, $"https://corsproxy.io/?{encodedUrl}"); - using var response = await client.SendAsync(request); - var content = await response.Content.ReadAsStringAsync(); - - var match = Regex.Match(content, ""); - if (match.Success) + if (!string.IsNullOrEmpty(result.DisplayName)) { - result.Link = match.Groups[1].Value.Replace("*", "%2A").Replace("`", "%60"); + + if (result.ItemType == "Constructor") + { + result.Link = Regex.Replace(result.DisplayName, @"\(.*\)", ".%23ctor%2A"); + } + else if (result.ItemType == "Method") + { + result.Link = Regex.Replace(result.DisplayName, @"\(.*\)", "%2A"); + } + else + { + result.Link = result.DisplayName; + } + + result.Link = ReplaceGenericArity(result.Link ?? string.Empty); } - result.Index = index++; + result.Index = ResultsToRender.Count + 1; ResultsToRender.Add(result); StateHasChanged(); } @@ -130,6 +138,68 @@ } } + private static string ReplaceGenericArity(string value) + { + var builder = new StringBuilder(); + + for (var index = 0; index < value.Length; index++) + { + if (value[index] != '<') + { + builder.Append(value[index]); + continue; + } + + var depth = 1; + var endIndex = index + 1; + + while (endIndex < value.Length && depth > 0) + { + if (value[endIndex] == '<') + { + depth++; + } + else if (value[endIndex] == '>') + { + depth--; + } + + endIndex++; + } + + if (depth > 0) + { + builder.Append(value[index]); + continue; + } + + var genericArguments = value[(index + 1)..(endIndex - 1)]; + var arity = 1; + var argumentDepth = 0; + + foreach (var character in genericArguments) + { + if (character == '<') + { + argumentDepth++; + } + else if (character == '>') + { + argumentDepth--; + } + else if (character == ',' && argumentDepth == 0) + { + arity++; + } + } + + builder.Append($"%60{arity}"); + index = endIndex - 1; + } + + return builder.ToString(); + } + private void ClearUI() { ResultsToRender.Clear(); From e9521ec808709834d944cf60d8f4a3a7f5e58999 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Tue, 6 Oct 2026 14:53:36 -0400 Subject: [PATCH 2/2] Updates --- .../Pages/Home.razor | 124 +++++++----------- BlazorWebAssemblyXrefGenerator/Program.cs | 2 +- 2 files changed, 47 insertions(+), 79 deletions(-) diff --git a/BlazorWebAssemblyXrefGenerator/Pages/Home.razor b/BlazorWebAssemblyXrefGenerator/Pages/Home.razor index e760bf19b..7281f66ee 100644 --- a/BlazorWebAssemblyXrefGenerator/Pages/Home.razor +++ b/BlazorWebAssemblyXrefGenerator/Pages/Home.razor @@ -11,17 +11,6 @@

Search

- - - - - - - - - - -
@@ -69,16 +58,36 @@ private SearchResults? SearchResultItems { get; set; } private List ResultsToRender { get; set; } = new(); public string? message; - private string? dotNetVersion; private const int MaxResults = 22; private bool isSearching = false; + private static readonly Regex NestedBracketRegex = new Regex( + @"\[(?:[^\[\]]+|(?\[)|(?<-Open>\]))*(?(Open)(?!))\]", + RegexOptions.Compiled + ); + + private static readonly Regex TypeSegmentRegex = new Regex( + @"(?<=-)(\d+)", + RegexOptions.Compiled + ); + + private static readonly Regex NestedAngleBracketRegex = new Regex( + @"<(?:[^<>]+|(?<)|(?<-Open>>))*(?(Open)(?!))>", + RegexOptions.Compiled + ); + + private static readonly Regex NestedParenthesesRegex = new Regex( + @"\((?:[^()]+|(?\()|(?<-Open>\)))+(?(Open)(?!))\)", + RegexOptions.Compiled + ); + protected override void OnInitialized() => Model ??= new(); public async Task GetSearchResults() { + isSearching = true; ResultsToRender.Clear(); message = string.Empty; @@ -93,29 +102,46 @@ try { - SearchResultItems = await apiClient.GetFromJsonAsync($"api/apibrowser/dotnet/search?search={Model.SearchText}"); + var urlEncodedSearchText = WebUtility.UrlEncode(Model.SearchText); + + SearchResultItems = await apiClient.GetFromJsonAsync($"api/apibrowser/dotnet/search?search={urlEncodedSearchText}"); if (SearchResultItems?.Results?.Any() == true) { foreach (var result in SearchResultItems.Results.Take(MaxResults)) { - if (!string.IsNullOrEmpty(result.DisplayName)) + if (!string.IsNullOrEmpty(result.DisplayName) && !string.IsNullOrEmpty(result.Url)) { - if (result.ItemType == "Constructor") { result.Link = Regex.Replace(result.DisplayName, @"\(.*\)", ".%23ctor%2A"); + //result.Link = NestedParenthesesRegex.Replace(result.Link, ".%23ctor%2A"); } else if (result.ItemType == "Method") { + result.Link = Regex.Replace(result.DisplayName, @"\(.*\)", "%2A"); + //result.Link = NestedParenthesesRegex.Replace(result.Link, ".%2A"); + } + else if (result.ItemType == "Property") + { + result.Link = NestedBracketRegex.Replace(result.DisplayName, "%2A"); } else { result.Link = result.DisplayName; } - result.Link = ReplaceGenericArity(result.Link ?? string.Empty); + var captureTypeSegmentMatch = TypeSegmentRegex.Match(result.Url).Value; + + if (captureTypeSegmentMatch is not null) + { + result.Link = Regex.Replace(result.Link, @"<.*>", $"%60{captureTypeSegmentMatch}"); + + //var angleBracketMatch = NestedAngleBracketRegex.Match(result.DisplayName); + //var angleBracketMatchValue = angleBracketMatch.Value; + //result.Link = NestedAngleBracketRegex.Replace(result.DisplayName, $"%60{angleBracketMatchValue}"); + } } result.Index = ResultsToRender.Count + 1; @@ -132,72 +158,14 @@ { message = "Bad Request! No results returned."; } - finally + catch (HttpRequestException ex) { - isSearching = false; + message = $"A general error occurred. {ex.Message}"; } - } - - private static string ReplaceGenericArity(string value) - { - var builder = new StringBuilder(); - - for (var index = 0; index < value.Length; index++) + finally { - if (value[index] != '<') - { - builder.Append(value[index]); - continue; - } - - var depth = 1; - var endIndex = index + 1; - - while (endIndex < value.Length && depth > 0) - { - if (value[endIndex] == '<') - { - depth++; - } - else if (value[endIndex] == '>') - { - depth--; - } - - endIndex++; - } - - if (depth > 0) - { - builder.Append(value[index]); - continue; - } - - var genericArguments = value[(index + 1)..(endIndex - 1)]; - var arity = 1; - var argumentDepth = 0; - - foreach (var character in genericArguments) - { - if (character == '<') - { - argumentDepth++; - } - else if (character == '>') - { - argumentDepth--; - } - else if (character == ',' && argumentDepth == 0) - { - arity++; - } - } - - builder.Append($"%60{arity}"); - index = endIndex - 1; + isSearching = false; } - - return builder.ToString(); } private void ClearUI() diff --git a/BlazorWebAssemblyXrefGenerator/Program.cs b/BlazorWebAssemblyXrefGenerator/Program.cs index d5ae81889..d2e0ef117 100644 --- a/BlazorWebAssemblyXrefGenerator/Program.cs +++ b/BlazorWebAssemblyXrefGenerator/Program.cs @@ -8,6 +8,6 @@ builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); -builder.Services.AddHttpClient("APIClient", client => client.BaseAddress = new Uri("https://learn.microsoft.com")); +builder.Services.AddHttpClient("APIClient", client => client.BaseAddress = new Uri("https://learn.microsoft.com/")); await builder.Build().RunAsync();