Repository: microsoft/kiota (csharp)

Issue:
Error when generating an API plugin
### What are you generating using Kiota, clients or plugins?

Kiota plugin

### In what context or format are you using Kiota?

Windows executable

### Client library/SDK language

None

### Describe the bug

I'm able to search and find the GitHub OpenAPI description and select the endpoints I care about, which are:
- /repos/{owner}/{repo}#GET
- /repos/{owner}/{repo}#PATCH
- /repos/{owner}/{repo}#DELETE

When trying to generate an "API Plugin" for the above endpoints, I got the following error:
![image](https://github.com/microsoft/kiota/assets/22648831/adec4435-72a9-49c7-8e7f-841f2a7ad501)

In the output folder, both generated files (plugin and sliced openapi) are wrong.
Plugin file has no functions nor runtimes objects.

```jsonc
{
  "schema_version": "v2",
  "name_for_human": "GitHub v3 REST API",
  "description_for_human": "GitHub\u0026apos;s v3 REST API.",
  "description_for_model": "GitHub\u0026apos;s v3 REST API.",
  "logo_url": "https://api.apis.guru/v2/cache/logo/https_twitter.com_github_profile_image.jpeg",
  "namespace": "githubrepo",
  "capabilities": {
    "localization": {}
  }
}
```

The sliced OpenAPI description has no "paths".

```yaml
openapi: 3.0.1
info:
  title: GitHub v3 REST API
  description: GitHub's v3 REST API.
  termsOfService: https://docs.github.com/articles/github-terms-of-service
  contact:
    name: Support
    url: https://support.github.com/contact?tags=dotcom-rest-api
  license:
    name: MIT
    url: https://spdx.org/licenses/MIT
  version: '1.1.4'
  x-apisguru-categories:
    - collaboration
    - developer_tools
  x-github-plan: api.github.com
  x-logo:
    url: https://api.apis.guru/v2/cache/logo/https_twitter.com_github_profile_image.jpeg
  x-origin:
    - format: openapi
      url: https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json
      version: '3.0'
  x-providerName: github.com
  x-serviceName: api.github.com
servers:
  - url: https://api.github.com
paths: { }
components: ...
```

Using the same extension version I'm able to correctly generate an API Plugin for other GitHub endpoints, like `/search` node.
Also, after getting the above error, I'm not able to load a new OpenAPI description. For that, I need to close and reopen VS Code.

### Expected behavior

I should be able to generate an API plugin with functions and runtime for the selected endpoints as well as have a sliced OpenAPI description with only the selected endpoints in the paths

### How to reproduce

Just try to generate a plugin for all the following endpoints:
- /repos/{owner}/{repo}#GET
- /repos/{owner}/{repo}#PATCH
- /repos/{owner}/{repo}#DELETE

### Open API description file

_No response_

### Kiota Version

plugin feature

### Latest Kiota version known to work for scenario above?(Not required)

_No response_

### Known Workarounds

_No response_

### Configuration

_No response_

### Debug output

<details><summary>Click to expand log</summary>
```


<log output here>

```
</details>


### Other information

_No response_

Pull request:
Fixes https://github.com/microsoft/kiota/issues/4715

It updates the `ReplaceAllIndexesWithWildcard` to cater for scenarios where the indexer is the end of the path without a trailing slash. 

Normally, this hasn't been seen as an issue as the indexer usually matches the openApi description. However, in some scenarios such as the VS code extension, the paths displayed maybe cleaned up due to the inder deduplication logic and thus the functionality becomes more important.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 08dd3c5055..0985b86ce3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -42,6 +42,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Fixes a bug where models would be duplicated in some allOf scenarios [#4191](https://github.com/microsoft/kiota/issues/4191)
 - Fixes a bug where CLI Generation does not handle path parameters of type "string" and format "date", "date-time", "time", etc. [#4615](https://github.com/microsoft/kiota/issues/4615)
 - Fixes a bug where request executors would be missing Untyped parameters in dotnet [#4692](https://github.com/microsoft/kiota/issues/4692)
+- Fixes a bug where indexers in include/exclude patters were not normalized if the indexer was the last segment without a slash at the end [#4715](https://github.com/microsoft/kiota/issues/4715)
 - Fixes a bug where CLI generation doesnot handle parameters of type string array. [#4707](https://github.com/microsoft/kiota/issues/4707)
 
 ## [1.14.0] - 2024-05-02
diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs
index 9310c3c5c0..bb39714bf3 100644
--- a/src/Kiota.Builder/KiotaBuilder.cs
+++ b/src/Kiota.Builder/KiotaBuilder.cs
@@ -331,9 +331,9 @@ private async Task FinalizeWorkspaceAsync(Stopwatch sw, int stepId, OpenApiUrlTr
     }
     private readonly WorkspaceManagementService workspaceManagementService;
     private static readonly GlobComparer globComparer = new();
-    [GeneratedRegex(@"([\/\\])\{[\w\d-]+\}([\/\\])", RegexOptions.IgnoreCase | RegexOptions.Singleline, 2000)]
+    [GeneratedRegex(@"([\/\\])\{[\w\d-]+\}([\/\\])?", RegexOptions.IgnoreCase | RegexOptions.Singleline, 2000)]
     private static partial Regex MultiIndexSameLevelCleanupRegex();
-    private static string ReplaceAllIndexesWithWildcard(string path, uint depth = 10) => depth == 0 ? path : ReplaceAllIndexesWithWildcard(MultiIndexSameLevelCleanupRegex().Replace(path, "$1{*}$2"), depth - 1); // the bound needs to be greedy to avoid replacing anything else than single path parameters
+    internal static string ReplaceAllIndexesWithWildcard(string path, uint depth = 10) => depth == 0 ? path : ReplaceAllIndexesWithWildcard(MultiIndexSameLevelCleanupRegex().Replace(path, "$1{*}$2"), depth - 1); // the bound needs to be greedy to avoid replacing anything else than single path parameters
     private static Dictionary<Glob, HashSet<OperationType>> GetFilterPatternsFromConfiguration(HashSet<string> configPatterns)
     {
         return configPatterns.Select(static x =>


Test patch:
diff --git a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
index 1229f61547..7240e27a4f 100644
--- a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
+++ b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
@@ -8647,6 +8647,24 @@ public void CleansUpOperationIdAddsMissingOperationId()
         Assert.Equal("directory_administrativeunits_post", operations[1].Value.OperationId);
     }
 
+    [Theory]
+    [InlineData("repos/{id}/", "repos/{*}/")] // normalish case
+    [InlineData("repos/{id}", "repos/{*}")]// no trailing slash
+    [InlineData("/repos/{id}", "/repos/{*}")]// no trailing slash(slash at begining).
+    [InlineData("repos/{id}/dependencies/{dep-id}", "repos/{*}/dependencies/{*}")]// multiple indexers
+    [InlineData("/repos/{id}/dependencies/{dep-id}/", "/repos/{*}/dependencies/{*}/")]// multiple indexers(slash at begining and end).
+    [InlineData("/repos/{id}/dependencies/{dep-id}", "/repos/{*}/dependencies/{*}")]// multiple indexers(slash at begining).
+    [InlineData("repos/{id}/{dep-id}", "repos/{*}/{*}")]// indexers following each other.
+    [InlineData("/repos/{id}/{dep-id}", "/repos/{*}/{*}")]// indexers following each other(slash at begining).
+    [InlineData("repos/msft", "repos/msft")]// no indexers
+    [InlineData("/repos", "/repos")]// no indexers(slash at begining).
+    [InlineData("repos", "repos")]// no indexers
+    public void ReplacesAllIndexesWithWildcard(string inputPath, string expectedGlob)
+    {
+        var resultGlob = KiotaBuilder.ReplaceAllIndexesWithWildcard(inputPath);
+        Assert.Equal(expectedGlob, resultGlob);
+    }
+
     [Fact]
     public void CleansUpOperationIdChangesOperationId()
     {