-
Notifications
You must be signed in to change notification settings - Fork 863
Repair XREF gen tool #671
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Repair XREF gen tool #671
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| @page "/" | ||
| @using System.Net | ||
| @using System.Text | ||
| @using System.Text.RegularExpressions | ||
| @inject IHttpClientFactory ClientFactory | ||
|
|
||
|
|
@@ -10,17 +11,6 @@ | |
| <div class="panel panel-default"> | ||
| <div class="panel-heading"> | ||
| <h3 class="panel-title">Search</h3> | ||
| <span style="float:right"> | ||
| <InputSelect @bind-Value="dotNetVersion"> | ||
| <option>aspnetcore-10.0</option> | ||
| <option>aspnetcore-9.0</option> | ||
| <option>aspnetcore-8.0</option> | ||
| <option>aspnetcore-7.0</option> | ||
| <option>aspnetcore-6.0</option> | ||
| <option>aspnetcore-5.0</option> | ||
| <option>aspnetcore-3.1</option> | ||
| </InputSelect> | ||
| </span> | ||
| </div> | ||
| <div class="panel-body"> | ||
| <div class="form-group"> | ||
|
|
@@ -68,7 +58,6 @@ | |
| private SearchResults? SearchResultItems { get; set; } | ||
| private List<Result> ResultsToRender { get; set; } = new(); | ||
| public string? message; | ||
| private string? dotNetVersion; | ||
|
|
||
| private const int MaxResults = 22; | ||
|
|
||
|
|
@@ -83,6 +72,7 @@ | |
| message = string.Empty; | ||
|
|
||
| var apiClient = ClientFactory.CreateClient("APIClient"); | ||
|
|
||
| if (string.IsNullOrEmpty(Model?.SearchText) || apiClient == null) | ||
| { | ||
| isSearching = false; | ||
|
|
@@ -91,26 +81,32 @@ | |
|
|
||
| try | ||
| { | ||
| SearchResultItems = await apiClient.GetFromJsonAsync<SearchResults>($"api/apibrowser/dotnet/search?api-version=0.2&search={Model.SearchText}"); | ||
| SearchResultItems = await apiClient.GetFromJsonAsync<SearchResults>($"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, "<meta name=\"ms.assetid\" 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); | ||
|
Copilot marked this conversation as resolved.
|
||
| StateHasChanged(); | ||
| } | ||
|
|
@@ -137,6 +133,68 @@ | |
| message = string.Empty; | ||
| } | ||
|
|
||
| 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}"); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this work for generic methods as well? Isn't the convention there to use two backticks rather than one?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You might be right about it failing in that case. Copilot generated the method, and I'm just trying to quickly get the tool back online. I'll check on how the API Browser expects the links for generic methods and get back to you. |
||
| index = endIndex - 1; | ||
| } | ||
|
|
||
| return builder.ToString(); | ||
| } | ||
|
|
||
| public class FormModel | ||
| { | ||
| public string? SearchText { get; set; } = string.Empty; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this produce the correct string for a constructor? Isn't there an extra name in the result? (copilot flagged this before in the PR)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think Copilot is incorrect. Consider
ControllerBase's ctor. It shows up as ...Therefore, I don't think it has an extra name in the result.
Funny thing is that we have ZERO live ctors cross-linked in our almost 900 articles at this time, so I don't have a live example to check to know 100% for sure.Correction: We do have live ctors ... my first filter didn't catch them. I've confirmed it: There are no double names in the links. For example ...
... at ...
https://learn.microsoft.com/en-us/aspnet/core/breaking-changes/5/localization-pubternal-apis-removed?view=aspnetcore-10.0#affected-apis
... correctly resolves to a cross-link that loads the API Browser to the ctor at ...
https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.localization.resourcemanagerstringlocalizer.-ctor?view=net-11.0-pp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, thanks for the explanation.