diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 8e1fc56376..af6046f4b4 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -45,6 +45,7 @@ jobs: - python description: - "./tests/Kiota.Builder.IntegrationTests/InheritingErrors.yaml" + - "./tests/Kiota.Builder.IntegrationTests/EnumHandling.yaml" - "./tests/Kiota.Builder.IntegrationTests/NoUnderscoresInModel.yaml" - "./tests/Kiota.Builder.IntegrationTests/ToDoApi.yaml" - "./tests/Kiota.Builder.IntegrationTests/GeneratesUritemplateHints.yaml" @@ -59,7 +60,7 @@ jobs: - "apisguru::docusign.net" - "apisguru::github.com:api.github.com" - "apisguru::apis.guru" - + steps: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ef449d8dd..24efe3bdb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added a warning message in the CLI when using preview languages. [#4316](https://github.com/microsoft/kiota/issues/4316) - Added support for handling untyped Json content in C#,Golang, TypeScript and Java. [#2319](https://github.com/microsoft/kiota/issues/2319) - Added TypeScript typecheck suppression to `.ts` files where unused imports cause build fail in projects which use `noUnusedLocals: true` compiler option. [#4397](https://github.com/microsoft/kiota/issues/4397) +- Fixed TypeScript generation bug when returning enums from endpoints. [#4426](https://github.com/microsoft/kiota/issues/4426) ### Changed diff --git a/it/typescript/package.json b/it/typescript/package.json index 00b45f9a04..e4e98c2856 100644 --- a/it/typescript/package.json +++ b/it/typescript/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "license": "MIT", "scripts": { - "build": "node ./build/esbuild.js --dev", + "build": "tsc -noEmit && node ./build/esbuild.js --dev", "build:meta": "node ./build/esbuild.js --dev --meta", "build:meta:prod": "node ./build/esbuild.js --meta", "build:prod": "node ./build/esbuild.js", @@ -41,4 +41,4 @@ "express": "^4.19.2", "node-fetch": "^2.7.0" } -} +} \ No newline at end of file diff --git a/it/typescript/src/app/app.ts b/it/typescript/src/app/app.ts index d724061b91..919dcfe915 100644 --- a/it/typescript/src/app/app.ts +++ b/it/typescript/src/app/app.ts @@ -3,7 +3,7 @@ import { Logger } from './common/logger'; import { DeviceCodeCredential } from '@azure/identity'; import { FetchRequestAdapter } from '@microsoft/kiota-http-fetchlibrary'; import { AzureIdentityAuthenticationProvider } from '@microsoft/kiota-authentication-azure'; -import { type ApiClient } from './client/apiClient'; +import { createApiClient } from './client/apiClient'; export class App { static run(): App { @@ -19,7 +19,7 @@ export class App { }); const authProvider = new AzureIdentityAuthenticationProvider(cred, ['Mail.Read']); const requestAdapter = new FetchRequestAdapter(authProvider); - const client = new ApiClient(requestAdapter); + const client = createApiClient(requestAdapter); Logger.log(`${client}`); return app; } diff --git a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs index 7a3d3aa436..6ef8b678b6 100644 --- a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs +++ b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs @@ -1103,9 +1103,25 @@ protected static void AddEnumObject(CodeElement currentElement) } CrawlTree(currentElement, AddEnumObject); } - protected static void AddEnumObjectUsings(CodeElement currentElement) { + if (currentElement is CodeProperty codeProperty && codeProperty.Kind is CodePropertyKind.RequestBuilder && codeProperty.Type is CodeType codeType && codeType.TypeDefinition is CodeClass codeClass) + { + foreach (var propertyMethod in codeClass.Methods) + { + if (propertyMethod.ReturnType is CodeType ct && ct.TypeDefinition is CodeEnum codeEnum) + { + codeClass.AddUsing(new CodeUsing + { + Name = codeEnum.Name, + Declaration = new CodeType + { + TypeDefinition = codeEnum.CodeEnumObject + } + }); + } + } + } if (currentElement is CodeFunction codeFunction && codeFunction.OriginalLocalMethod.IsOfKind(CodeMethodKind.Deserializer, CodeMethodKind.Serializer)) { foreach (var propertyEnum in codeFunction.OriginalMethodParentClass.Properties.Select(static x => x.Type).OfType().Select(static x => x.TypeDefinition).OfType()) diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeConstantWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeConstantWriter.cs index 70467c719c..c78bb77f6d 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeConstantWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeConstantWriter.cs @@ -119,7 +119,14 @@ private void WriteRequestsMetadataConstant(CodeConstant codeElement, LanguageWri } writer.WriteLine($"adapterMethodName: \"{GetSendRequestMethodName(isVoid, isStream, executorMethod.ReturnType.IsCollection, isPrimitive, isEnum)}\","); if (isEnum) - writer.WriteLine($"enumObject: {executorMethod.ReturnType.Name.ToFirstCharacterUpperCase()},"); + { + string enumObjectName = string.Empty; + if (executorMethod.ReturnType is CodeType ct && ct.TypeDefinition is CodeEnum ce) + { + enumObjectName = ce.CodeEnumObject!.Name; + } + writer.WriteLine($"enumObject: {enumObjectName!.ToFirstCharacterUpperCase()},"); + } else if (!isVoid) writer.WriteLine($"responseBodyFactory: {GetTypeFactory(isVoid, isStream, executorMethod, writer)},"); var sanitizedRequestBodyContentType = executorMethod.RequestBodyContentType.SanitizeDoubleQuote(); diff --git a/tests/Kiota.Builder.IntegrationTests/EnumHandling.yaml b/tests/Kiota.Builder.IntegrationTests/EnumHandling.yaml new file mode 100644 index 0000000000..43a6cb0eb2 --- /dev/null +++ b/tests/Kiota.Builder.IntegrationTests/EnumHandling.yaml @@ -0,0 +1,29 @@ +openapi: 3.0.3 +info: + title: Test + version: 3.0.x + description: Testing enum handling. + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0 +paths: + "/play": + get: + responses: + "200": + content: + application/json: + schema: + "$ref": "#/components/schemas/MoveType" + description: A move + description: "Play a move" +components: + schemas: + MoveType: + description: "" + enum: + - ROCK + - PAPER + - SCISSORS + type: string + example: ROCK diff --git a/tests/Kiota.Builder.IntegrationTests/GenerateSample.cs b/tests/Kiota.Builder.IntegrationTests/GenerateSample.cs index 7fba8971a5..e501197158 100644 --- a/tests/Kiota.Builder.IntegrationTests/GenerateSample.cs +++ b/tests/Kiota.Builder.IntegrationTests/GenerateSample.cs @@ -116,6 +116,28 @@ public async Task GeneratesErrorsInliningParents(GenerationLanguage language) }; await new KiotaBuilder(logger, configuration, _httpClient).GenerateClientAsync(new()); } + [InlineData(GenerationLanguage.CSharp)] + [InlineData(GenerationLanguage.Java)] + [InlineData(GenerationLanguage.Go)] + [InlineData(GenerationLanguage.Ruby)] + [InlineData(GenerationLanguage.Python)] + [InlineData(GenerationLanguage.TypeScript)] + [InlineData(GenerationLanguage.PHP)] + [Theory] + public async Task GeneratesCorrectEnums(GenerationLanguage language) + { + var logger = LoggerFactory.Create(builder => + { + }).CreateLogger(); + + var configuration = new GenerationConfiguration + { + Language = language, + OpenAPIFilePath = GetAbsolutePath("EnumHandling.yaml"), + OutputPath = $".\\Generated\\EnumHandling\\{language}", + }; + await new KiotaBuilder(logger, configuration, _httpClient).GenerateClientAsync(new()); + } [InlineData(GenerationLanguage.Java)] [Theory] public async Task GeneratesIdiomaticChildrenNames(GenerationLanguage language) diff --git a/tests/Kiota.Builder.IntegrationTests/Kiota.Builder.IntegrationTests.csproj b/tests/Kiota.Builder.IntegrationTests/Kiota.Builder.IntegrationTests.csproj index 5fa8150c95..490f14c266 100644 --- a/tests/Kiota.Builder.IntegrationTests/Kiota.Builder.IntegrationTests.csproj +++ b/tests/Kiota.Builder.IntegrationTests/Kiota.Builder.IntegrationTests.csproj @@ -49,6 +49,9 @@ PreserveNewest + + PreserveNewest + \ No newline at end of file