diff --git a/CHANGELOG.md b/CHANGELOG.md index e9db905a57..61cabd0020 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Fixed a bug where path parameters deduplication would create collisions on sub path segments. [#3757](https://github.com/microsoft/kiota/issues/3757) - Moved from net7 to net8. - Fixed a bug where import statements for additionalDataHolder and enumSet are missing when BackingStore is enabled in java. [#3643](https://github.com/microsoft/kiota/pull/3643) - Fixed a bug where getBackingStore method body was malformed for java. [#3643](https://github.com/microsoft/kiota/pull/3643) diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs index 5fe1a230ed..3158ae59e7 100644 --- a/src/Kiota.Builder/KiotaBuilder.cs +++ b/src/Kiota.Builder/KiotaBuilder.cs @@ -549,10 +549,15 @@ private void MergeIndexNodesAtSameLevel(OpenApiUrlTreeNode node) if (indexNodes.Length > 1) { var indexNode = indexNodes[0]; + node.Children.Remove(indexNode.Key); + var newSegmentParameterName = $"{{{node.Segment.CleanupSymbolName()}-id}}"; + indexNode.Value.Path = indexNode.Value.Path.Replace(indexNode.Key, newSegmentParameterName, StringComparison.OrdinalIgnoreCase); + node.Children.Add(newSegmentParameterName, indexNode.Value); + CopyNodeIntoOtherNode(indexNode.Value, indexNode.Value, indexNode.Key, newSegmentParameterName); foreach (var child in indexNodes.Except(new[] { indexNode })) { node.Children.Remove(child.Key); - CopyNodeIntoOtherNode(child.Value, indexNode.Value, child.Key, indexNode.Key); + CopyNodeIntoOtherNode(child.Value, indexNode.Value, child.Key, newSegmentParameterName); } } @@ -567,8 +572,8 @@ private void CopyNodeIntoOtherNode(OpenApiUrlTreeNode source, OpenApiUrlTreeNode if (!destination.Children.TryAdd(child.Key, child.Value)) CopyNodeIntoOtherNode(child.Value, destination.Children[child.Key], pathParameterNameToReplace, pathParameterNameReplacement); } - pathParameterNameToReplace = pathParameterNameToReplace.TrimStart('{').TrimEnd('}'); - pathParameterNameReplacement = pathParameterNameReplacement.TrimStart('{').TrimEnd('}'); + pathParameterNameToReplace = pathParameterNameToReplace.Trim('{', '}'); + pathParameterNameReplacement = pathParameterNameReplacement.Trim('{', '}'); foreach (var pathItem in source.PathItems) { foreach (var pathParameter in pathItem diff --git a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs index 61ae73c1a3..76d25f805b 100644 --- a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs +++ b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs @@ -6334,6 +6334,25 @@ public void SinglePathParametersAreDeduplicated() { Paths = new OpenApiPaths { + ["users/{foo}/careerAdvisor/{id}"] = new OpenApiPathItem + { + Operations = { + [OperationType.Get] = new OpenApiOperation + { + Responses = new OpenApiResponses { + ["200"] = new OpenApiResponse + { + Content = { + ["application/json"] = new OpenApiMediaType + { + Schema = userSchema + } + } + } + } + } + } + }, ["users/{id}/careerAdvisor"] = new OpenApiPathItem { Operations = { @@ -6390,12 +6409,17 @@ public void SinglePathParametersAreDeduplicated() Assert.NotNull(managerRB); var managerUrlTemplate = managerRB.FindChildByName("UrlTemplate", false); Assert.NotNull(managerUrlTemplate); - Assert.Equal("{+baseurl}/users/{id}/manager", managerUrlTemplate.DefaultValue.Trim('"')); + Assert.Equal("{+baseurl}/users/{users%2Did}/manager", managerUrlTemplate.DefaultValue.Trim('"')); var careerAdvisorRB = codeModel.FindNamespaceByName("ApiSdk.users.item.careerAdvisor").FindChildByName("CareerAdvisorRequestBuilder", false); Assert.NotNull(careerAdvisorRB); var careerAdvisorUrlTemplate = careerAdvisorRB.FindChildByName("UrlTemplate", false); Assert.NotNull(careerAdvisorUrlTemplate); - Assert.Equal("{+baseurl}/users/{id}/careerAdvisor", careerAdvisorUrlTemplate.DefaultValue.Trim('"')); + Assert.Equal("{+baseurl}/users/{users%2Did}/careerAdvisor", careerAdvisorUrlTemplate.DefaultValue.Trim('"')); + var careerAdvisorItemRB = codeModel.FindNamespaceByName("ApiSdk.users.item.careerAdvisor.item").FindChildByName("CareerAdvisorItemRequestBuilder", false); + Assert.NotNull(careerAdvisorItemRB); + var careerAdvisorItemUrlTemplate = careerAdvisorItemRB.FindChildByName("UrlTemplate", false); + Assert.NotNull(careerAdvisorItemUrlTemplate); + Assert.Equal("{+baseurl}/users/{users%2Did}/careerAdvisor/{id}", careerAdvisorItemUrlTemplate.DefaultValue.Trim('"')); } [Fact] public void AddReservedPathParameterSymbol()