From 73429c1b2450ac2f414dad94f424910a2fa8a3a0 Mon Sep 17 00:00:00 2001 From: Shem Ogumbe Date: Thu, 9 May 2024 11:57:04 +0300 Subject: [PATCH 1/5] update request configuration class (#2034) * Merge dev to master (#2013) Bump apidoctor from 1708be5 to 1916d8c (#2004) Add use import statements for PHP Snippets (#2000) Bump Microsoft.OpenApi.OData from 1.6.0 to 1.6.1 (#2007) Bump Microsoft.VisualStudio.Azure.Containers.Tools.Targets (#2008) Bump MSTest.TestFramework from 3.2.2 to 3.3.0 (#2009) Bump MSTest.TestFramework from 3.3.0 to 3.3.1 (#2011) Bump Microsoft.VisualStudio.Azure.Containers.Tools.Targets (#2010) Chore: change drop location (#2012) * Remove built request configiguation name * Update unit tests for updated request configuration name * Update imports to inlcude base request configuration * update tests --------- Co-authored-by: Millicent Achieng Co-authored-by: Charles Wahome --- .../PythonGeneratorTests.cs | 16 +++++++++------- .../PythonImportGeneratorTests.cs | 1 + .../LanguageGenerators/PythonGenerator.cs | 7 ++++++- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/CodeSnippetsReflection.OpenAPI.Test/PythonGeneratorTests.cs b/CodeSnippetsReflection.OpenAPI.Test/PythonGeneratorTests.cs index a56a4e569..6a9d86942 100644 --- a/CodeSnippetsReflection.OpenAPI.Test/PythonGeneratorTests.cs +++ b/CodeSnippetsReflection.OpenAPI.Test/PythonGeneratorTests.cs @@ -169,7 +169,7 @@ public async Task GeneratesSelectQueryParameters() var result = _generator.GenerateCodeSnippet(snippetModel); Assert.Contains("RequestBuilderGetQueryParameters(", result); Assert.Contains("select = [\"displayName\",\"id\"]", result); - Assert.Contains("RequestBuilderGetRequestConfiguration(", result); + Assert.Contains("RequestConfiguration(", result); Assert.Contains("query_parameters = query_params,", result); } [Fact] @@ -182,7 +182,7 @@ public async Task GeneratesCountBooleanQueryParameters() Assert.Contains("count = True", result); Assert.Contains("select = [\"displayName\",\"id\"]", result); Assert.DoesNotContain("\"true\"", result); - Assert.Contains("RequestBuilderGetRequestConfiguration(", result); + Assert.Contains("RequestConfiguration(", result); Assert.Contains("query_parameters = query_params,", result); } [Fact] @@ -211,7 +211,8 @@ public async Task GeneratesRequestHeaders() requestPayload.Headers.Add("ConsistencyLevel", "eventual"); var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1SnippetMetadata()); var result = _generator.GenerateCodeSnippet(snippetModel); - Assert.Contains("request_configuration = GroupsRequestBuilder.GroupsRequestBuilderGetRequestConfiguration()", result); + Assert.Contains("request_configuration = RequestConfiguration()", result); + Assert.Contains("from kiota_abstractions.base_request_configuration import RequestConfiguration", result); Assert.Contains("request_configuration.headers.add(\"ConsistencyLevel\", \"eventual\")", result); } [Fact] @@ -244,7 +245,8 @@ public async Task GeneratesSnippetForRequestWithDeltaAndSkipToken() var result = _generator.GenerateCodeSnippet(snippetModel); Assert.Contains("DeltaRequestBuilderGetQueryParameters(", result); Assert.Contains("skiptoken = \"R0usmcCM996atia_s\",", result); - Assert.Contains("request_configuration = DeltaRequestBuilder.DeltaRequestBuilderGetRequestConfiguration(", result); + Assert.Contains("request_configuration = RequestConfiguration(", result); + Assert.Contains("from kiota_abstractions.base_request_configuration import RequestConfiguration", result); Assert.Contains("query_parameters = query_params,", result); Assert.Contains("request_configuration.headers.add(\"Prefer\", \"odata.maxpagesize=2\")", result); Assert.Contains("result = await graph_client.me.calendar_view.delta.get", result); @@ -651,7 +653,7 @@ public async Task CorrectlyHandlesOdataFunction() Assert.Contains("await graph_client.users.delta.get(request_configuration = request_configuration)", result); Assert.Contains("query_params = DeltaRequestBuilder.DeltaRequestBuilderGetQueryParameters(", result); Assert.Contains("select = [\"displayName\",\"jobTitle\",\"mobilePhone\"]", result); - Assert.Contains("request_configuration = DeltaRequestBuilder.DeltaRequestBuilderGetRequestConfiguration(", result); + Assert.Contains("request_configuration = RequestConfiguration(", result); } [Fact] public async Task CorrectlyHandlesDateTimeOffsetInUrl() @@ -886,7 +888,7 @@ public async Task CorrectlyHandlesTypeFromInUrl() Assert.Contains("query_params = MailFoldersRequestBuilder.MailFoldersRequestBuilderGetQueryParameters(", result); Assert.Contains("include_hidden_folders = \"true\"", result); - Assert.Contains("request_configuration = MailFoldersRequestBuilder.MailFoldersRequestBuilderGetRequestConfiguration(", result); + Assert.Contains("request_configuration = RequestConfiguration(", result); } [Fact] public async Task MatchesPathWithPathParameter() @@ -1197,6 +1199,6 @@ public async Task GeneratesCorrectRequestBuilderNameForIndexedCollections() var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1SnippetMetadata()); var result = _generator.GenerateCodeSnippet(snippetModel); Assert.Contains("query_params = UserItemRequestBuilder.UserItemRequestBuilderGetQueryParameters(", result); - Assert.Contains("request_configuration = UserItemRequestBuilder.UserItemRequestBuilderGetRequestConfiguration(", result); + Assert.Contains("request_configuration = RequestConfiguration(", result); } } diff --git a/CodeSnippetsReflection.OpenAPI.Test/PythonImportGeneratorTests.cs b/CodeSnippetsReflection.OpenAPI.Test/PythonImportGeneratorTests.cs index 832c02877..fa049c6b1 100644 --- a/CodeSnippetsReflection.OpenAPI.Test/PythonImportGeneratorTests.cs +++ b/CodeSnippetsReflection.OpenAPI.Test/PythonImportGeneratorTests.cs @@ -18,6 +18,7 @@ public async Task GeneratesRequestBuilderImports() var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1SnippetMetadata()); var result = _generator.GenerateCodeSnippet(snippetModel); Assert.Contains("from msgraph import GraphServiceClient", result); + Assert.Contains("from kiota_abstractions.base_request_configuration import RequestConfiguration", result); Assert.Contains("from msgraph.generated.users.item.calendar.events.events_request_builder import EventsRequestBuilder", result); } diff --git a/CodeSnippetsReflection.OpenAPI/LanguageGenerators/PythonGenerator.cs b/CodeSnippetsReflection.OpenAPI/LanguageGenerators/PythonGenerator.cs index 4ca42749a..f7857c177 100644 --- a/CodeSnippetsReflection.OpenAPI/LanguageGenerators/PythonGenerator.cs +++ b/CodeSnippetsReflection.OpenAPI/LanguageGenerators/PythonGenerator.cs @@ -18,6 +18,7 @@ public class PythonGenerator : ILanguageGenerator ReservedTypeNames = new(StringComparer.OrdinalIgnoreCase) @@ -79,6 +80,7 @@ private static HashSet GetImportStatements(SnippetModel snippetModel) { const string modelImportPrefix = "from msgraph.generated.models"; const string requestBuilderImportPrefix = "from msgraph.generated"; + const string BaseRequestConfigImport = "from kiota_abstractions.base_request_configuration import RequestConfiguration"; var snippetImports = new HashSet(); @@ -96,6 +98,7 @@ private static HashSet GetImportStatements(SnippetModel snippetModel) var namespaceParts = import.ModelProperty.NamespaceName.Split('.').Select((s, i) => i == import.ModelProperty.NamespaceName.Split('.').Length - 1 ? s.ToSnakeCase() : s.ToLowerInvariant()); var importString = $"{requestBuilderImportPrefix}.{string.Join(".", namespaceParts)}.{typeDefinition.ToSnakeCase()} import {typeDefinition}"; snippetImports.Add($"{importString.Replace(".me.", ".users.item.")}"); + } else{ snippetImports.Add($"{modelImportPrefix}.{typeDefinition.ToSnakeCase()} import {typeDefinition}"); @@ -119,6 +122,8 @@ private static HashSet GetImportStatements(SnippetModel snippetModel) { //construct path to request builder snippetImports.Add($"{requestBuilderImportPrefix}{Regex.Replace(import.Path.Replace(".me.", ".users.item."), @"(\B[A-Z])", "_$1", RegexOptions.Compiled, TimeSpan.FromSeconds(60)).ToLower()}.{import.RequestBuilderName.ToSnakeCase()} import {import.RequestBuilderName}"); + snippetImports.Add($"{BaseRequestConfigImport}"); + } break; } @@ -188,7 +193,7 @@ private static string GetRequestConfiguration(SnippetCodeGraph codeGraph, Indent if (codeGraph.HasParameters() || codeGraph.HasHeaders()) { snippetBuilder.AppendLine(queryParamsPayload); - snippetBuilder.Append($"{RequestConfigurationVarName} = {requestBuilderName}.{requestConfigurationName}("); + snippetBuilder.Append($"{RequestConfigurationVarName} = {RequestConfigurationType}("); if (codeGraph.HasParameters()) { From 794ea1835c48f37be353c48c599ced6cb5d3f057 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 May 2024 09:27:18 +0300 Subject: [PATCH 2/5] Bump Microsoft.AspNetCore.Authorization from 8.0.4 to 8.0.5 (#2049) Bumps [Microsoft.AspNetCore.Authorization](https://github.com/dotnet/aspnetcore) from 8.0.4 to 8.0.5. - [Release notes](https://github.com/dotnet/aspnetcore/releases) - [Changelog](https://github.com/dotnet/aspnetcore/blob/main/docs/ReleasePlanning.md) - [Commits](https://github.com/dotnet/aspnetcore/compare/v8.0.4...v8.0.5) --- updated-dependencies: - dependency-name: Microsoft.AspNetCore.Authorization dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- GraphWebApi/GraphWebApi.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GraphWebApi/GraphWebApi.csproj b/GraphWebApi/GraphWebApi.csproj index 20248a669..2a4c12c1e 100644 --- a/GraphWebApi/GraphWebApi.csproj +++ b/GraphWebApi/GraphWebApi.csproj @@ -46,7 +46,7 @@ - + From 76db4b2ace8f39eb45c19c695d8ad517cb72e34b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 May 2024 12:52:40 +0300 Subject: [PATCH 3/5] Bump Microsoft.AspNetCore.Authentication.JwtBearer from 8.0.4 to 8.0.5 (#2048) Bumps [Microsoft.AspNetCore.Authentication.JwtBearer](https://github.com/dotnet/aspnetcore) from 8.0.4 to 8.0.5. - [Release notes](https://github.com/dotnet/aspnetcore/releases) - [Changelog](https://github.com/dotnet/aspnetcore/blob/main/docs/ReleasePlanning.md) - [Commits](https://github.com/dotnet/aspnetcore/compare/v8.0.4...v8.0.5) --- updated-dependencies: - dependency-name: Microsoft.AspNetCore.Authentication.JwtBearer dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- GraphWebApi/GraphWebApi.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GraphWebApi/GraphWebApi.csproj b/GraphWebApi/GraphWebApi.csproj index 2a4c12c1e..7946a5855 100644 --- a/GraphWebApi/GraphWebApi.csproj +++ b/GraphWebApi/GraphWebApi.csproj @@ -45,7 +45,7 @@ - + From 4d352d4823920046e4cc9ff571a6102b9c4fa60d Mon Sep 17 00:00:00 2001 From: silaskenneth Date: Thu, 16 May 2024 16:17:45 +0300 Subject: [PATCH 4/5] Fix model import paths + Add support for enum imports (#2047) * Initial work on fixing paths. * Remove unused test. * Add imports for DateOnly, TimeOnly and Enums. * Fix issue with spelling. * Do slight refactor to improve style. * Fix more issues with the snippets. * Take care of corner cases. --- .../PhpGeneratorTests.cs | 5 ++ .../PythonGeneratorTests.cs | 4 + .../LanguageGenerators/PhpGenerator.cs | 73 ++++++++++++++++--- .../LanguageGenerators/PythonGenerator.cs | 44 +++++++++-- .../LanguageGenerators/SnippetImports.cs | 2 +- 5 files changed, 112 insertions(+), 16 deletions(-) diff --git a/CodeSnippetsReflection.OpenAPI.Test/PhpGeneratorTests.cs b/CodeSnippetsReflection.OpenAPI.Test/PhpGeneratorTests.cs index 2e39b7aa5..c9cf5c2d5 100644 --- a/CodeSnippetsReflection.OpenAPI.Test/PhpGeneratorTests.cs +++ b/CodeSnippetsReflection.OpenAPI.Test/PhpGeneratorTests.cs @@ -75,6 +75,8 @@ public async Task IncludesRequestBodyClassName() var snippetModel = new SnippetModel(requestPayload, ServiceRootBetaUrl, await GetBetaSnippetMetadata()); var result = _generator.GenerateCodeSnippet(snippetModel); Assert.Contains("AddPasswordPostRequestBody", result); + Assert.Contains(@"use Microsoft\Graph\Beta\GraphServiceClient;", result); + Assert.Contains(@"use Microsoft\Graph\Beta\Generated\Models\PasswordCredential;", result); } [Fact] @@ -847,6 +849,9 @@ public async Task GenerateWithCustomDateAndTimeTypes() }; var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1SnippetMetadata()); var result = _generator.GenerateCodeSnippet(snippetModel); + Assert.Contains(@"use Microsoft\Kiota\Abstractions\Types\Date;", result); + Assert.Contains(@"use Microsoft\Kiota\Abstractions\Types\Time;", result); + Assert.Contains(@"use Microsoft\Graph\Generated\Models\AutomaticUpdateMode;", result); Assert.Contains("->setQualityUpdatesPauseStartDate(new Date('2016-12-31'))", result); Assert.Contains("->setScheduledInstallTime(new Time('11:59:31.3170000'))", result); } diff --git a/CodeSnippetsReflection.OpenAPI.Test/PythonGeneratorTests.cs b/CodeSnippetsReflection.OpenAPI.Test/PythonGeneratorTests.cs index 6a9d86942..f35a6c5eb 100644 --- a/CodeSnippetsReflection.OpenAPI.Test/PythonGeneratorTests.cs +++ b/CodeSnippetsReflection.OpenAPI.Test/PythonGeneratorTests.cs @@ -878,6 +878,7 @@ public async Task GeneratesCorrectTypeInCollectionInitializer() { Assert.Contains("scope = RuleBasedSubjectSet(", result); Assert.Contains("tasks = [", result); Assert.Contains("Task(", result); + Assert.Contains("from msgraph.generated.models.lifecycle_workflow_category import LifecycleWorkflowCategory", result); } [Fact] public async Task CorrectlyHandlesTypeFromInUrl() @@ -936,6 +937,7 @@ public async Task GeneratesObjectInitializationWithCallToSetters() var result = _generator.GenerateCodeSnippet(snippetModel); Assert.Contains("select = [\"displayName\",\"mailNickName\"],", result); Assert.Contains("account_enabled = True", result); + Assert.Contains("from msgraph import GraphServiceClient", result); } [Fact] public async Task IncludesRequestBodyClassName() @@ -950,6 +952,8 @@ public async Task IncludesRequestBodyClassName() var snippetModel = new SnippetModel(requestPayload, ServiceRootBetaUrl, await GetBetaSnippetMetadata()); var result = _generator.GenerateCodeSnippet(snippetModel); Assert.Contains("request_body = AddPasswordPostRequestBody(", result); + Assert.Contains("from msgraph_beta.generated.models.password_credential import PasswordCredential", result); + Assert.Contains("from msgraph_beta import GraphServiceClient", result); } [Fact] public async Task FindsPathItemsWithDifferentCasing() diff --git a/CodeSnippetsReflection.OpenAPI/LanguageGenerators/PhpGenerator.cs b/CodeSnippetsReflection.OpenAPI/LanguageGenerators/PhpGenerator.cs index dd97e0b49..8368d78c6 100644 --- a/CodeSnippetsReflection.OpenAPI/LanguageGenerators/PhpGenerator.cs +++ b/CodeSnippetsReflection.OpenAPI/LanguageGenerators/PhpGenerator.cs @@ -121,12 +121,16 @@ public string GenerateCodeSnippet(SnippetModel snippetModel) } private static HashSet GetImportStatements(SnippetModel snippetModel) { - const string modelImportPrefix = "use Microsoft\\Graph\\Generated\\Models"; - const string requestBuilderImportPrefix = "use Microsoft\\Graph\\Generated"; - - var snippetImports = new HashSet(); + var packagePrefix = snippetModel.ApiVersion switch + { + "v1.0" => @"Microsoft\Graph", + "beta" => @"Microsoft\Graph\Beta", + }; + var modelImportPrefix = $@"use {packagePrefix}\Generated\Models"; + var requestBuilderImportPrefix = $@"use {packagePrefix}\Generated"; + const string customTypesPrefix = @"use Microsoft\Kiota\Abstractions\Types"; - snippetImports.Add("use Microsoft\\Graph\\GraphServiceClient;"); + var snippetImports = new HashSet { $@"use {packagePrefix}\GraphServiceClient;" }; var imports = ImportsGenerator.GenerateImportTemplates(snippetModel); foreach (var import in imports) @@ -134,20 +138,61 @@ private static HashSet GetImportStatements(SnippetModel snippetModel) switch (import.Kind) { case ImportKind.Model: + if (import.ModelProperty.PropertyType is PropertyType.DateOnly or PropertyType.TimeOnly) + { + snippetImports.Add($"{customTypesPrefix}\\{GetPropertyTypeName(import.ModelProperty)};"); + continue; + } var typeDefinition = import.ModelProperty.TypeDefinition; - if (typeDefinition != null){ - snippetImports.Add($"{modelImportPrefix}\\{typeDefinition};"); + const string modelsNamespaceName = "models.microsoft.graph"; + var modelNamespaceStringLen = modelsNamespaceName.Length; + var modelNamespace = import.ModelProperty.NamespaceName; + var inModelsNamespace = + modelNamespace.Equals(modelsNamespaceName, + StringComparison.OrdinalIgnoreCase); + var nested = !inModelsNamespace && modelNamespace.StartsWith(modelsNamespaceName); + // This takes care of models in nested namespaces inside the model namespace for instance + // models inside IdentityGovernance namespace + var othersParts = nested switch + { + true => import.ModelProperty.NamespaceName[modelNamespaceStringLen..] + .Split('.', StringSplitOptions.RemoveEmptyEntries) + .Select(static x => x.ToFirstCharacterUpperCase()) + .Aggregate(static (x, y) => $@"{x}\{y}"), + false => string.Empty + }; + + var namespaceValue = !string.IsNullOrEmpty(othersParts) ? $@"\{othersParts}" : string.Empty; + if (typeDefinition != null) + { + if (inModelsNamespace) + { + snippetImports.Add($@"{modelImportPrefix}{namespaceValue}\{typeDefinition};"); + } + else + { + var imported = import.ModelProperty.NamespaceName.Split('.') + .Select(x => x.ToFirstCharacterUpperCase()) + .Aggregate(static (a, b) => $@"{a}\{b}") + .Replace(@"Me\", @"Users\Item\"); + snippetImports.Add($@"{requestBuilderImportPrefix}\{imported}\{typeDefinition}"); + } // check if model has a nested namespace and append it to the import statement + continue; // Move to the next import. + } + + if (import.ModelProperty.PropertyType == PropertyType.Enum) + { + snippetImports.Add($@"{modelImportPrefix}{namespaceValue}\{import.ModelProperty.Name.ToFirstCharacterUpperCase()};"); } break; - case ImportKind.Path: if (!string.IsNullOrEmpty(import.Path) && !string.IsNullOrEmpty(import.RequestBuilderName)) { //construct path to request builder var importPath = import.Path.Split('.') .Select(static s => s.ToFirstCharacterUpperCase()).ToArray(); - snippetImports.Add($"{requestBuilderImportPrefix}{string.Join("\\", importPath).Replace("\\Me\\", "\\Users\\Item\\")}\\{import.RequestBuilderName}{import.HttpMethod.ToLowerInvariant().ToFirstCharacterUpperCase()}RequestConfiguration;"); + snippetImports.Add($@"{requestBuilderImportPrefix}{string.Join(@"\", importPath).Replace(@"\Me\", @"\Users\Item\")}\{import.RequestBuilderName}{import.HttpMethod.ToLowerInvariant().ToFirstCharacterUpperCase()}RequestConfiguration;"); } break; } @@ -567,4 +612,14 @@ private static string GetFluentApiPath(IEnumerable nodes, Sn return result.EndsWith("()()") ? result[..^2] : result; } + + private static string GetPropertyTypeName(CodeProperty property) + { + return property.PropertyType switch + { + PropertyType.DateOnly => "Date", + PropertyType.TimeOnly => "Time", + _ => property.TypeDefinition + }; + } } diff --git a/CodeSnippetsReflection.OpenAPI/LanguageGenerators/PythonGenerator.cs b/CodeSnippetsReflection.OpenAPI/LanguageGenerators/PythonGenerator.cs index f7857c177..a2a5677da 100644 --- a/CodeSnippetsReflection.OpenAPI/LanguageGenerators/PythonGenerator.cs +++ b/CodeSnippetsReflection.OpenAPI/LanguageGenerators/PythonGenerator.cs @@ -78,13 +78,18 @@ public string GenerateCodeSnippet(SnippetModel snippetModel) } private static HashSet GetImportStatements(SnippetModel snippetModel) { - const string modelImportPrefix = "from msgraph.generated.models"; - const string requestBuilderImportPrefix = "from msgraph.generated"; + var packageName = snippetModel.ApiVersion switch + { + "v1.0" => "msgraph", + "beta" => "msgraph_beta", + }; + var modelImportPrefix = $"from {packageName}.generated.models"; + var requestBuilderImportPrefix = $"from {packageName}.generated"; const string BaseRequestConfigImport = "from kiota_abstractions.base_request_configuration import RequestConfiguration"; var snippetImports = new HashSet(); - snippetImports.Add("from msgraph import GraphServiceClient"); + snippetImports.Add($"from {packageName} import GraphServiceClient"); var imports = ImportsGenerator.GenerateImportTemplates(snippetModel); foreach (var import in imports) @@ -92,18 +97,45 @@ private static HashSet GetImportStatements(SnippetModel snippetModel) switch (import.Kind) { case ImportKind.Model: + // We don't use custom DateOnly and TimeOnly types for python snippets. + if (import.ModelProperty.PropertyType is PropertyType.DateOnly or PropertyType.TimeOnly) + continue; var typeDefinition = import.ModelProperty.TypeDefinition; + const string modelsNamespaceName = "models.microsoft.graph"; + var modelNamespaceStringLen = modelsNamespaceName.Length; + var importModelNamespace = import.ModelProperty.NamespaceName; + var inModelsNamespace = importModelNamespace.Equals(modelsNamespaceName); + + var nested = !inModelsNamespace && importModelNamespace.StartsWith(modelsNamespaceName); + // This takes care of models in nested namespaces inside the model namespace for instance + // models inside IdentityGovernance namespace + var othersParts = nested switch + { + true => importModelNamespace[modelNamespaceStringLen..] + .Split('.', StringSplitOptions.RemoveEmptyEntries) + .Select(static x => x.ToSnakeCase()) + .Aggregate(static (x, y) => $"{x}.{y}"), + false => string.Empty + }; + + var namespaceValue = !string.IsNullOrEmpty(othersParts) ? $".{othersParts}" : string.Empty; if (typeDefinition != null){ if(typeDefinition.EndsWith("RequestBody",StringComparison.OrdinalIgnoreCase)){ - var namespaceParts = import.ModelProperty.NamespaceName.Split('.').Select((s, i) => i == import.ModelProperty.NamespaceName.Split('.').Length - 1 ? s.ToSnakeCase() : s.ToLowerInvariant()); + var namespaceParts = importModelNamespace.Split('.').Select((s, i) => i == import.ModelProperty.NamespaceName.Split('.').Length - 1 ? s.ToSnakeCase() : s.ToLowerInvariant()); var importString = $"{requestBuilderImportPrefix}.{string.Join(".", namespaceParts)}.{typeDefinition.ToSnakeCase()} import {typeDefinition}"; snippetImports.Add($"{importString.Replace(".me.", ".users.item.")}"); - } else{ - snippetImports.Add($"{modelImportPrefix}.{typeDefinition.ToSnakeCase()} import {typeDefinition}"); + snippetImports.Add($"{modelImportPrefix}{namespaceValue}.{typeDefinition.ToSnakeCase()} import {typeDefinition}"); } } + + if (import.ModelProperty.PropertyType == PropertyType.Enum) + { + var enumName = import.ModelProperty.Value.Split('.').First(); + snippetImports.Add( + $"{modelImportPrefix}.{enumName.ToSnakeCase()} import {enumName}"); + } break; diff --git a/CodeSnippetsReflection.OpenAPI/LanguageGenerators/SnippetImports.cs b/CodeSnippetsReflection.OpenAPI/LanguageGenerators/SnippetImports.cs index 75ec8bc64..faf4c3c5d 100644 --- a/CodeSnippetsReflection.OpenAPI/LanguageGenerators/SnippetImports.cs +++ b/CodeSnippetsReflection.OpenAPI/LanguageGenerators/SnippetImports.cs @@ -79,7 +79,7 @@ public static List GenerateImportTemplates(SnippetModel snippet private static void AddModelImportTemplates(CodeProperty node, List imports) { - if (!string.IsNullOrEmpty(node.NamespaceName)) + if (!string.IsNullOrEmpty(node.NamespaceName) || (node.PropertyType is PropertyType.DateOnly or PropertyType.TimeOnly)) { imports.Add(new ImportTemplate { From aeedd2355218411e51dd529ea36c3cfbb331ee40 Mon Sep 17 00:00:00 2001 From: Ronald K <43806892+rkodev@users.noreply.github.com> Date: Fri, 17 May 2024 11:03:09 +0300 Subject: [PATCH 5/5] Fix functions as object names in go snippets (#2051) * Fix functions as object names in go snippets * fix static vars in linq --- .../GoGeneratorTests.cs | 14 ++++++ .../LanguageGenerators/GoGenerator.cs | 49 ++++++++++++++++--- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/CodeSnippetsReflection.OpenAPI.Test/GoGeneratorTests.cs b/CodeSnippetsReflection.OpenAPI.Test/GoGeneratorTests.cs index c4180bdda..576678d35 100644 --- a/CodeSnippetsReflection.OpenAPI.Test/GoGeneratorTests.cs +++ b/CodeSnippetsReflection.OpenAPI.Test/GoGeneratorTests.cs @@ -433,6 +433,20 @@ public async Task WritesEmptyPrimitiveArrays() { Assert.Contains("SetIncludeUserActions", result); } [Fact] + public async Task WriteCorrectFunctionNameWithParametersAsModelName() + { + const string messageObject = "{\r\n\"displayName\": \"Display name\"\r\n}"; + using var requestPayload = new HttpRequestMessage(HttpMethod.Patch, $"{ServiceRootUrl}/applications(uniqueName='app-65278')") + { + Content = new StringContent(messageObject, Encoding.UTF8, "application/json") + }; + requestPayload.Headers.Add("Prefer", "create-if-missing"); + var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetBetaSnippetMetadata()); + var result = _generator.GenerateCodeSnippet(snippetModel); + Assert.Contains("graphapplicationswithuniquename \"github.com/microsoftgraph/msgraph-sdk-go/applicationswithuniquename\"", result); + Assert.Contains("graphapplicationswithuniquename.ApplicationsWithUniqueNameRequestBuilderPatchRequestConfiguration", result); + } + [Fact] public async Task WriteCorrectTypesForFilterParameters() { using var requestPayload = new HttpRequestMessage(HttpMethod.Get, diff --git a/CodeSnippetsReflection.OpenAPI/LanguageGenerators/GoGenerator.cs b/CodeSnippetsReflection.OpenAPI/LanguageGenerators/GoGenerator.cs index e5d8958e0..59428b031 100644 --- a/CodeSnippetsReflection.OpenAPI/LanguageGenerators/GoGenerator.cs +++ b/CodeSnippetsReflection.OpenAPI/LanguageGenerators/GoGenerator.cs @@ -1,21 +1,19 @@ using System; +using System.Collections; using System.Collections.Generic; -using System.Linq; using System.Collections.Immutable; +using System.Linq; using System.Text; +using System.Text.RegularExpressions; using CodeSnippetsReflection.OpenAPI.ModelGraph; using CodeSnippetsReflection.StringExtensions; using Microsoft.OpenApi.Services; -using System.Text.RegularExpressions; -using System.Collections; namespace CodeSnippetsReflection.OpenAPI.LanguageGenerators { public class GoGenerator : ILanguageGenerator { private const string clientVarName = "graphClient"; - private const string clientVarType = "GraphServiceClientWithCredentials"; - private const string clientFactoryVariables = "cred, scopes"; private const string requestBodyVarName = "requestBody"; private const string requestHeadersVarName = "headers"; private const string optionsParameterVarName = "options"; @@ -29,6 +27,10 @@ public class GoGenerator : ILanguageGenerator private static readonly Regex PropertyNameRegex = new Regex(@"@(.*)", RegexOptions.Compiled, TimeSpan.FromMilliseconds(200)); + private static readonly Regex FunctionRegex = new Regex(@"(\w+)\(([^)]*)\)", RegexOptions.Compiled, TimeSpan.FromMilliseconds(200)); + + private static readonly Regex ParamRegex = new Regex(@"(\w+)\s*=\s*'[^']*'", RegexOptions.Compiled, TimeSpan.FromMilliseconds(200)); + static IImmutableSet GetNativeTypes() { return ImmutableHashSet.Create("string", "int", "float"); @@ -142,9 +144,24 @@ private static void TraverseProperty(CodeProperty property, Action private static String ProcessNameSpaceName(String nameSpace) { - return (nameSpace != null ? nameSpace.Split(".", StringSplitOptions.RemoveEmptyEntries) + if (String.IsNullOrEmpty(nameSpace)) + return ""; + + // process function names and parameters + var functionNameMatch = FunctionRegex.Match(nameSpace); + if (functionNameMatch.Success) + { + var paramMatches = ParamRegex.Matches(functionNameMatch.Groups[2].Value); + var paramNames = paramMatches.Cast().Select(static m => m.Groups[1].Value).ToList(); + + return functionNameMatch.Groups[1].Value + "With" + string.Join("With", paramNames); + } + + var processedName = (nameSpace.Split(".", StringSplitOptions.RemoveEmptyEntries) .Select(x => x.Equals("Me", StringComparison.OrdinalIgnoreCase) ? "Users" : x) - .Aggregate((current, next) => current + "." + next) : "models").Replace(".microsoft.graph", ""); + .Aggregate(static (current, next) => current + "." + next)).Replace(".microsoft.graph", ""); + + return processedName; } private static String ProcessFinalNameSpaceName(String nameSpace) @@ -306,7 +323,7 @@ private static string GetNestedObjectName(IEnumerable nodes) if (x.Segment.IsCollectionIndex()) return "Item"; else - return x.Segment.ToFirstCharacterUpperCase(); + return EscapeFunctionNames(x.Segment.ToFirstCharacterUpperCase()); }) .Aggregate(static (x, y) => { @@ -316,6 +333,22 @@ private static string GetNestedObjectName(IEnumerable nodes) }); } + private static string EscapeFunctionNames(String objectName) + { + if (String.IsNullOrEmpty(objectName)) + return objectName; + + var match = FunctionRegex.Match(objectName); + if (match.Success) + { + var paramMatches = ParamRegex.Matches(match.Groups[2].Value); + var paramNames = paramMatches.Cast().Select(static m => m.Groups[1].Value.ToFirstCharacterUpperCase()).ToList(); + + return match.Groups[1].Value + "With" + string.Join("With", paramNames); + } + return objectName; + } + private static string evaluateParameter(CodeProperty param) { if (param.PropertyType == PropertyType.Array)