diff --git a/CHANGELOG.md b/CHANGELOG.md index 38c5ea33e4..5de990cbd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,12 +9,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Added auto-generated comment for TypeScript generation. [#3244](https://github.com/microsoft/kiota/issues/3244) + ### Changed - Localhost based descriptions are not cached anymore to facilitate development workflows. [#3316](https://github.com/microsoft/kiota/issues/3316) +- Changed parameter order in with_url method body to match the signature of RequestBuilder constructor in Python. [#3328](https://github.com/microsoft/kiota/issues/3328 +- Removed redundant undefined qualifier in TypeScript for properties. [#3244](https://github.com/microsoft/kiota/issues/3244) +- The default status code response is now used as 4XX and 5XX when those class responses are not provided in the description. [#3245](https://github.com/microsoft/kiota/issues/3245) - Adds codes files in typescript to reduce number of generated files. [#2116](https://github.com/microsoft/kiota/issues/2116) - ## [1.6.1] - 2023-09-11 ### Changed diff --git a/src/Kiota.Builder/CodeDOM/CodeMethod.cs b/src/Kiota.Builder/CodeDOM/CodeMethod.cs index f8db7511cc..1d2cc952db 100644 --- a/src/Kiota.Builder/CodeDOM/CodeMethod.cs +++ b/src/Kiota.Builder/CodeDOM/CodeMethod.cs @@ -263,6 +263,11 @@ public IOrderedEnumerable> ErrorMappings return errorMappings.OrderBy(static x => x.Key); } } + public bool HasErrorMappingCode(string code) + { + ArgumentException.ThrowIfNullOrEmpty(code); + return errorMappings.ContainsKey(code); + } public DeprecationInformation? Deprecation { diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs index a8fc56d995..9c64aa8cb9 100644 --- a/src/Kiota.Builder/KiotaBuilder.cs +++ b/src/Kiota.Builder/KiotaBuilder.cs @@ -1224,31 +1224,44 @@ openApiExtension is OpenApiPrimaryErrorMessageExtension primaryErrorMessageExten private const string RequestBodyPlainTextContentType = "text/plain"; private static readonly HashSet noContentStatusCodes = new() { "201", "202", "204", "205" }; private static readonly HashSet errorStatusCodes = new(Enumerable.Range(400, 599).Select(static x => x.ToString(CultureInfo.InvariantCulture)) - .Concat(new[] { "4XX", "5XX" }), StringComparer.OrdinalIgnoreCase); - + .Concat(new[] { FourXXError, FiveXXError }), StringComparer.OrdinalIgnoreCase); + private const string FourXXError = "4XX"; + private const string FiveXXError = "5XX"; private void AddErrorMappingsForExecutorMethod(OpenApiUrlTreeNode currentNode, OpenApiOperation operation, CodeMethod executorMethod) { foreach (var response in operation.Responses.Where(x => errorStatusCodes.Contains(x.Key))) { - var errorCode = response.Key.ToUpperInvariant(); - var errorSchema = response.Value.GetResponseSchema(config.StructuredMimeTypes); - if (errorSchema != null && modelsNamespace != null) - { - var parentElement = string.IsNullOrEmpty(response.Value.Reference?.Id) && string.IsNullOrEmpty(errorSchema.Reference?.Id) - ? (CodeElement)executorMethod - : modelsNamespace; - var errorType = CreateModelDeclarations(currentNode, errorSchema, operation, parentElement, $"{errorCode}Error", response: response.Value); - if (errorType is CodeType codeType && - codeType.TypeDefinition is CodeClass codeClass && - !codeClass.IsErrorDefinition) - { - codeClass.IsErrorDefinition = true; - } - if (errorType is null) - logger.LogWarning("Could not create error type for {Error} in {Operation}", errorCode, operation.OperationId); - else - executorMethod.AddErrorMapping(errorCode, errorType); + if (response.Value.GetResponseSchema(config.StructuredMimeTypes) is { } schema) + { + AddErrorMappingToExecutorMethod(currentNode, operation, executorMethod, schema, response.Value, response.Key.ToUpperInvariant()); + } + } + if (operation.Responses.TryGetValue("default", out var defaultResponse) && defaultResponse.GetResponseSchema(config.StructuredMimeTypes) is { } errorSchema) + { + if (!executorMethod.HasErrorMappingCode(FourXXError)) + AddErrorMappingToExecutorMethod(currentNode, operation, executorMethod, errorSchema, defaultResponse, FourXXError); + if (!executorMethod.HasErrorMappingCode(FiveXXError)) + AddErrorMappingToExecutorMethod(currentNode, operation, executorMethod, errorSchema, defaultResponse, FiveXXError); + } + } + private void AddErrorMappingToExecutorMethod(OpenApiUrlTreeNode currentNode, OpenApiOperation operation, CodeMethod executorMethod, OpenApiSchema errorSchema, OpenApiResponse response, string errorCode) + { + if (modelsNamespace != null) + { + var parentElement = string.IsNullOrEmpty(response.Reference?.Id) && string.IsNullOrEmpty(errorSchema.Reference?.Id) + ? (CodeElement)executorMethod + : modelsNamespace; + var errorType = CreateModelDeclarations(currentNode, errorSchema, operation, parentElement, $"{errorCode}Error", response: response); + if (errorType is CodeType codeType && + codeType.TypeDefinition is CodeClass codeClass && + !codeClass.IsErrorDefinition) + { + codeClass.IsErrorDefinition = true; } + if (errorType is null) + logger.LogWarning("Could not create error type for {Error} in {Operation}", errorCode, operation.OperationId); + else + executorMethod.AddErrorMapping(errorCode, errorType); } } private CodeTypeBase? GetExecutorMethodReturnType(OpenApiUrlTreeNode currentNode, OpenApiSchema? schema, OpenApiOperation operation, CodeClass parentClass) diff --git a/src/Kiota.Builder/Writers/ProprietableBlockExtensions.cs b/src/Kiota.Builder/Writers/ProprietableBlockExtensions.cs index 6c71045564..8500c1cea7 100644 --- a/src/Kiota.Builder/Writers/ProprietableBlockExtensions.cs +++ b/src/Kiota.Builder/Writers/ProprietableBlockExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using Kiota.Builder.CodeDOM; @@ -12,8 +13,14 @@ internal static class ProprietableBlockExtensions internal static string GetPrimaryMessageCodePath(this ProprietableBlock block, Func propertyNameNormalization, Func methodNameNormalization, - string pathSegment = ".") where TBlockKind : Enum where TBlockDeclaration : ProprietableBlockDeclaration, new() + string pathSegment = ".", + HashSet? visitedElements = default) where TBlockKind : Enum where TBlockDeclaration : ProprietableBlockDeclaration, new() { + visitedElements ??= new(); + if (visitedElements.Contains(block)) + return string.Empty; + else + visitedElements.Add(block); if (block is CodeInterface currentInterface) { if (currentInterface.Methods.FirstOrDefault(static x => isGetterMethod(x) && x.AccessedProperty is not null && isPrimaryErrorMessage(x.AccessedProperty)) is CodeMethod primaryErrorMessageMethod) @@ -22,10 +29,10 @@ internal static string GetPrimaryMessageCodePath( return propertyNameNormalization(primaryErrorMessageProperty); else if (currentInterface.Methods .Where(isGetterMethod) - .Select(x => new { Value = x.ReturnType is CodeType codeType && codeType.TypeDefinition is CodeInterface codeInterface && codeInterface.GetPrimaryMessageCodePath(propertyNameNormalization, methodNameNormalization, pathSegment) is string segment && !string.IsNullOrEmpty(segment) ? $"{methodNameNormalization(x)}{pathSegment}{segment}" : string.Empty, IsMethod = true }) + .Select(x => new { Value = x.ReturnType is CodeType codeType && codeType.TypeDefinition is CodeInterface codeInterface && codeInterface.GetPrimaryMessageCodePath(propertyNameNormalization, methodNameNormalization, pathSegment, visitedElements) is string segment && !string.IsNullOrEmpty(segment) ? $"{methodNameNormalization(x)}{pathSegment}{segment}" : string.Empty, IsMethod = true }) .Union(currentInterface.Properties .Where(isCustomProperty) - .Select(x => new { Value = x.Type is CodeType codeType && codeType.TypeDefinition is CodeInterface codeInterface && codeInterface.GetPrimaryMessageCodePath(propertyNameNormalization, methodNameNormalization, pathSegment) is string segment && !string.IsNullOrEmpty(segment) ? $"{propertyNameNormalization(x)}{pathSegment}{segment}" : string.Empty, IsMethod = false })) + .Select(x => new { Value = x.Type is CodeType codeType && codeType.TypeDefinition is CodeInterface codeInterface && codeInterface.GetPrimaryMessageCodePath(propertyNameNormalization, methodNameNormalization, pathSegment, visitedElements) is string segment && !string.IsNullOrEmpty(segment) ? $"{propertyNameNormalization(x)}{pathSegment}{segment}" : string.Empty, IsMethod = false })) .OrderBy(static x => x.IsMethod) .ThenBy(static x => x.Value, StringComparer.OrdinalIgnoreCase) .FirstOrDefault(static x => !string.IsNullOrEmpty(x.Value)) is { } primaryMessageCodePath) @@ -40,10 +47,10 @@ internal static string GetPrimaryMessageCodePath( return propertyNameNormalization(primaryErrorMessageProperty); else if (currentClass.Methods .Where(isGetterMethod) - .Select(x => new { Value = x.ReturnType is CodeType codeType && codeType.TypeDefinition is CodeClass codeClass && codeClass.GetPrimaryMessageCodePath(propertyNameNormalization, methodNameNormalization, pathSegment) is string segment && !string.IsNullOrEmpty(segment) ? $"{methodNameNormalization(x)}{pathSegment}{segment}" : string.Empty, IsMethod = true }) + .Select(x => new { Value = x.ReturnType is CodeType codeType && codeType.TypeDefinition is CodeClass codeClass && codeClass.GetPrimaryMessageCodePath(propertyNameNormalization, methodNameNormalization, pathSegment, visitedElements) is string segment && !string.IsNullOrEmpty(segment) ? $"{methodNameNormalization(x)}{pathSegment}{segment}" : string.Empty, IsMethod = true }) .Union(currentClass.Properties .Where(isCustomProperty) - .Select(x => new { Value = x.Type is CodeType codeType && codeType.TypeDefinition is CodeClass codeClass && codeClass.GetPrimaryMessageCodePath(propertyNameNormalization, methodNameNormalization, pathSegment) is string segment && !string.IsNullOrEmpty(segment) ? $"{propertyNameNormalization(x)}{pathSegment}{segment}" : string.Empty, IsMethod = false })) + .Select(x => new { Value = x.Type is CodeType codeType && codeType.TypeDefinition is CodeClass codeClass && codeClass.GetPrimaryMessageCodePath(propertyNameNormalization, methodNameNormalization, pathSegment, visitedElements) is string segment && !string.IsNullOrEmpty(segment) ? $"{propertyNameNormalization(x)}{pathSegment}{segment}" : string.Empty, IsMethod = false })) .OrderBy(static x => x.IsMethod) .ThenBy(static x => x.Value, StringComparer.OrdinalIgnoreCase) .FirstOrDefault(static x => !string.IsNullOrEmpty(x.Value)) is { } primaryMessageCodePath) diff --git a/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs index ae2a137e8b..9c04fbd605 100644 --- a/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs @@ -114,7 +114,7 @@ private void WriteRawUrlBuilderBody(CodeClass parentClass, CodeMethod codeElemen { var rawUrlParameter = codeElement.Parameters.OfKind(CodeParameterKind.RawUrl) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RawUrl parameter"); var requestAdapterProperty = parentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RequestAdapter property"); - writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}({rawUrlParameter.Name.ToSnakeCase()}, self.{requestAdapterProperty.Name.ToSnakeCase()})"); + writer.WriteLine($"return {parentClass.Name.ToFirstCharacterUpperCase()}(self.{requestAdapterProperty.Name.ToSnakeCase()}, {rawUrlParameter.Name.ToSnakeCase()})"); } private const string DiscriminatorMappingVarName = "mapping_value"; diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeBlockEndWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeBlockEndWriter.cs index b867201b9e..ad1e6d07e9 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeBlockEndWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeBlockEndWriter.cs @@ -2,13 +2,18 @@ using Kiota.Builder.CodeDOM; namespace Kiota.Builder.Writers.TypeScript; -public class CodeBlockEndWriter : ICodeElementWriter +public class CodeBlockEndWriter : BaseElementWriter { - public void WriteCodeElement(BlockEnd codeElement, LanguageWriter writer) + public CodeBlockEndWriter(TypeScriptConventionService conventionService) : base(conventionService) + { + } + public override void WriteCodeElement(BlockEnd codeElement, LanguageWriter writer) { ArgumentNullException.ThrowIfNull(codeElement); ArgumentNullException.ThrowIfNull(writer); if (codeElement.Parent is CodeNamespace) return; writer.CloseBlock(); + if (codeElement.Parent?.Parent is CodeNamespace) + conventions.WriteAutoGeneratedEnd(writer); } } diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeClassDeclarationWriter.cs index 56d0de672e..bba31ba362 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeClassDeclarationWriter.cs @@ -16,6 +16,8 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit { ArgumentNullException.ThrowIfNull(codeElement); ArgumentNullException.ThrowIfNull(writer); + if (codeElement.Parent?.Parent is CodeNamespace) + conventions.WriteAutoGeneratedStart(writer); var parentNamespace = codeElement.GetImmediateParentOfType(); if (codeElement.Parent?.Parent is not CodeFile) diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs index 21d5931a40..170950e5d7 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs @@ -22,11 +22,15 @@ public override void WriteCodeElement(CodeFunction codeElement, LanguageWriter w ArgumentNullException.ThrowIfNull(codeElement); if (codeElement.OriginalLocalMethod == null) throw new InvalidOperationException($"{nameof(codeElement.OriginalLocalMethod)} should not be null"); ArgumentNullException.ThrowIfNull(writer); + if (codeElement.Parent is not CodeNamespace && codeElement.Parent is not CodeFile) throw new InvalidOperationException("the parent of a function should be a namespace or file"); if (codeElement.Parent is CodeNamespace) + { + conventions.WriteAutoGeneratedStart(writer); _codeUsingWriter.WriteCodeElement(codeElement.StartBlock.Usings, codeElement.GetImmediateParentOfType(), writer); - + } + var codeMethod = codeElement.OriginalLocalMethod; var returnType = codeMethod.Kind != CodeMethodKind.Factory ? conventions.GetTypeString(codeMethod.ReturnType, codeElement) : string.Empty; diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeInterfaceDeclarationWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeInterfaceDeclarationWriter.cs index c2f3f1be0e..efbbd4bec5 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeInterfaceDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeInterfaceDeclarationWriter.cs @@ -4,28 +4,28 @@ using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; -namespace Kiota.Builder.Writers.TypeScript +namespace Kiota.Builder.Writers.TypeScript; +public class CodeInterfaceDeclarationWriter : BaseElementWriter { - public class CodeInterfaceDeclarationWriter : BaseElementWriter + private readonly CodeUsingWriter _codeUsingWriter; + public CodeInterfaceDeclarationWriter(TypeScriptConventionService conventionService, string clientNamespaceName) : base(conventionService) { - private readonly CodeUsingWriter _codeUsingWriter; - public CodeInterfaceDeclarationWriter(TypeScriptConventionService conventionService, string clientNamespaceName) : base(conventionService) - { - _codeUsingWriter = new(clientNamespaceName); - } + _codeUsingWriter = new(clientNamespaceName); + } - public override void WriteCodeElement(InterfaceDeclaration codeElement, LanguageWriter writer) + public override void WriteCodeElement(InterfaceDeclaration codeElement, LanguageWriter writer) + { + ArgumentNullException.ThrowIfNull(codeElement); + ArgumentNullException.ThrowIfNull(writer); + + var parentNamespace = codeElement.GetImmediateParentOfType(); + if (codeElement.Parent?.Parent is CodeNamespace) { - ArgumentNullException.ThrowIfNull(codeElement); - ArgumentNullException.ThrowIfNull(writer); - - var parentNamespace = codeElement.GetImmediateParentOfType(); - - if (codeElement.Parent?.Parent is not CodeFile) - _codeUsingWriter.WriteCodeElement(codeElement.Usings, parentNamespace, writer); - - var derivation = codeElement.Implements.Any() ? $" extends {codeElement.Implements.Select(static x => x.Name).Aggregate(static (x, y) => x + ", " + y)}" : string.Empty; - writer.StartBlock($"export interface {codeElement.Name.ToFirstCharacterUpperCase()}{derivation} {{"); + conventions.WriteAutoGeneratedStart(writer); + _codeUsingWriter.WriteCodeElement(codeElement.Usings, parentNamespace, writer); } + + var derivation = codeElement.Implements.Any() ? $" extends {codeElement.Implements.Select(static x => x.Name).Aggregate(static (x, y) => x + ", " + y)}" : string.Empty; + writer.StartBlock($"export interface {codeElement.Name.ToFirstCharacterUpperCase()}{derivation} {{"); } } diff --git a/src/Kiota.Builder/Writers/TypeScript/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodePropertyWriter.cs index 20e4cbc36a..f12b8815df 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodePropertyWriter.cs @@ -30,7 +30,7 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w private static void WriteCodePropertyForInterface(CodeProperty codeElement, LanguageWriter writer, string returnType, bool isFlagEnum) { - writer.WriteLine($"{codeElement.Name.ToFirstCharacterLowerCase()}?: {returnType}{(isFlagEnum ? "[]" : string.Empty)}{(codeElement.Type.IsNullable ? " | undefined" : string.Empty)};"); + writer.WriteLine($"{codeElement.Name.ToFirstCharacterLowerCase()}?: {returnType}{(isFlagEnum ? "[]" : string.Empty)};"); } private void WriteCodePropertyForClass(CodeProperty codeElement, CodeClass parentClass, LanguageWriter writer, string returnType, bool isFlagEnum) @@ -45,7 +45,7 @@ private void WriteCodePropertyForClass(CodeProperty codeElement, CodeClass paren writer.CloseBlock(); break; default: - writer.WriteLine($"{conventions.GetAccessModifier(codeElement.Access)} {codeElement.NamePrefix}{codeElement.Name.ToFirstCharacterLowerCase()}{(codeElement.Type.IsNullable ? "?" : string.Empty)}: {returnType}{(isFlagEnum ? "[]" : string.Empty)}{(codeElement.Type.IsNullable ? " | undefined" : string.Empty)};"); + writer.WriteLine($"{conventions.GetAccessModifier(codeElement.Access)} {codeElement.NamePrefix}{codeElement.Name.ToFirstCharacterLowerCase()}{(codeElement.Type.IsNullable ? "?" : string.Empty)}: {returnType}{(isFlagEnum ? "[]" : string.Empty)};"); break; } } diff --git a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs index bad753c134..5d0d63f64c 100644 --- a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs +++ b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs @@ -15,6 +15,17 @@ public TypeScriptConventionService(LanguageWriter languageWriter) { writer = languageWriter; } + internal void WriteAutoGeneratedStart(LanguageWriter writer) + { + writer.WriteLine("// tslint:disable"); + writer.WriteLine("// eslint-disable"); + writer.WriteLine("// Generated by Microsoft Kiota"); + } + internal void WriteAutoGeneratedEnd(LanguageWriter writer) + { + writer.WriteLine("// tslint:enable"); + writer.WriteLine("// eslint-enable"); + } private readonly LanguageWriter writer; public override string StreamTypeName => "ArrayBuffer"; public override string VoidTypeName => "void"; diff --git a/src/Kiota.Builder/Writers/TypeScript/TypeScriptWriter.cs b/src/Kiota.Builder/Writers/TypeScript/TypeScriptWriter.cs index aea7e1a7e3..0e0c0a7d0f 100644 --- a/src/Kiota.Builder/Writers/TypeScript/TypeScriptWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/TypeScriptWriter.cs @@ -9,7 +9,7 @@ public TypeScriptWriter(string rootPath, string clientNamespaceName, bool usesBa PathSegmenter = new TypeScriptPathSegmenter(rootPath, clientNamespaceName); var conventionService = new TypeScriptConventionService(this); AddOrReplaceCodeElementWriter(new CodeClassDeclarationWriter(conventionService, clientNamespaceName)); - AddOrReplaceCodeElementWriter(new CodeBlockEndWriter()); + AddOrReplaceCodeElementWriter(new CodeBlockEndWriter(conventionService)); AddOrReplaceCodeElementWriter(new CodeEnumWriter(conventionService)); AddOrReplaceCodeElementWriter(new CodeMethodWriter(conventionService, usesBackingStore)); AddOrReplaceCodeElementWriter(new CodeFunctionWriter(conventionService, clientNamespaceName)); diff --git a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs index 4fdb78f5c1..08857a7638 100644 --- a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs +++ b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs @@ -2089,6 +2089,115 @@ public void DoesntAddSuffixesToErrorTypesWhenComponents() Assert.Null(codeModel.FindChildByName("tasks5XXError")); } [Fact] + public void UsesDefaultAs4XXAnd5XXWhenAbsent() + { + var errorSchema = new OpenApiSchema + { + Type = "object", + Properties = new Dictionary { + { + "errorId", new OpenApiSchema { + Type = "string" + } + } + }, + Reference = new OpenApiReference + { + Id = "microsoft.graph.error", + Type = ReferenceType.Schema + }, + UnresolvedReference = false + }; + var errorResponse = new OpenApiResponse + { + Content = + { + ["application/json"] = new OpenApiMediaType + { + Schema = errorSchema + } + }, + Reference = new OpenApiReference + { + Id = "microsoft.graph.error", + Type = ReferenceType.Response + }, + UnresolvedReference = false + }; + var document = new OpenApiDocument + { + Paths = new OpenApiPaths + { + ["tasks"] = new OpenApiPathItem + { + Operations = { + [OperationType.Get] = new OpenApiOperation + { + Responses = new OpenApiResponses + { + ["200"] = new OpenApiResponse + { + Content = + { + ["application/json"] = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Type = "object", + Properties = new Dictionary { + { + "progress", new OpenApiSchema{ + Type = "string", + } + } + } + } + } + } + }, + ["default"] = errorResponse, + ["401"] = errorResponse + } + } + } + } + }, + Components = new OpenApiComponents + { + Schemas = new Dictionary { + { + "microsoft.graph.error", errorSchema + } + }, + Responses = new Dictionary { + { + "microsoft.graph.error", errorResponse + } + } + }, + }; + var mockLogger = new Mock>(); + var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "Graph", ApiRootUrl = "https://localhost" }, _httpClient); + builder.SetOpenApiDocument(document); + var node = builder.CreateUriSpace(document); + var codeModel = builder.CreateSourceModel(node); + var executorMethod = codeModel.FindChildByName("get"); + Assert.NotNull(executorMethod); + Assert.NotEmpty(executorMethod.ErrorMappings); + var keys = executorMethod.ErrorMappings.Select(static x => x.Key).ToHashSet(); + Assert.Contains("4XX", keys); + Assert.Contains("401", keys); + Assert.Contains("5XX", keys); + var errorType = codeModel.FindChildByName("Error"); + Assert.NotNull(errorType); + Assert.True(errorType.IsErrorDefinition); + Assert.NotNull(errorType.FindChildByName("errorId")); + + Assert.Null(codeModel.FindChildByName("tasks401Error")); + Assert.Null(codeModel.FindChildByName("tasks4XXError")); + Assert.Null(codeModel.FindChildByName("tasks5XXError")); + } + [Fact] public void DoesntAddPropertyHolderOnNonAdditionalModels() { var weatherForecastSchema = new OpenApiSchema diff --git a/tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs index 9178cb74da..cb284b1c02 100644 --- a/tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs @@ -1509,6 +1509,7 @@ public void WritesWithUrl() writer.Write(method); var result = tw.ToString(); Assert.Contains($"return {parentClass.Name.ToFirstCharacterUpperCase()}", result); + Assert.Contains("request_adapter, raw_url", result); } [Fact] public void WritesConstructorForReqestBuilder() diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeClassDeclarationWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeClassDeclarationWriterTests.cs index e1dbdf0448..a33b8f81fe 100644 --- a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeClassDeclarationWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeClassDeclarationWriterTests.cs @@ -37,6 +37,14 @@ public void Dispose() GC.SuppressFinalize(this); } [Fact] + public void WritesAutoGenerationStart() + { + codeElementWriter.WriteCodeElement(parentClass.StartBlock, writer); + var result = tw.ToString(); + Assert.Contains("// eslint-disable", result); + Assert.Contains("// tslint:disable", result); + } + [Fact] public void WritesSimpleDeclaration() { codeElementWriter.WriteCodeElement(parentClass.StartBlock, writer); diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeClassEndWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeClassEndWriterTests.cs index f1af0e7b4c..1513b0e70c 100644 --- a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeClassEndWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeClassEndWriterTests.cs @@ -19,8 +19,8 @@ public class CodeClassEndWriterTests : IDisposable private readonly CodeClass parentClass; public CodeClassEndWriterTests() { - codeElementWriter = new CodeBlockEndWriter(); writer = LanguageWriter.GetLanguageWriter(GenerationLanguage.TypeScript, DefaultPath, DefaultName); + codeElementWriter = new CodeBlockEndWriter(new(writer)); tw = new StringWriter(); writer.SetTextWriter(tw); var root = CodeNamespace.InitRootNamespace(); @@ -45,12 +45,16 @@ public void ClosesNestedClasses() codeElementWriter.WriteCodeElement(child.EndBlock, writer); var result = tw.ToString(); Assert.Equal(1, result.Count(x => x == '}')); + Assert.DoesNotContain("// eslint-enable", result); + Assert.DoesNotContain("// tslint:enable", result); } [Fact] public void ClosesNonNestedClasses() { codeElementWriter.WriteCodeElement(parentClass.EndBlock, writer); var result = tw.ToString(); + Assert.Contains("// eslint-enable", result); + Assert.Contains("// tslint:enable", result); Assert.Equal(1, result.Count(x => x == '}')); } } diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs index aeca11d3f7..cb45af6c10 100644 --- a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs @@ -33,6 +33,31 @@ public void Dispose() GC.SuppressFinalize(this); } + [Fact] + public async Task WritesAutoGenerationStart() + { + var parentClass = TestHelper.CreateModelClass(root, "parentClass", true); + TestHelper.AddSerializationPropertiesToModelClass(parentClass); + await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.TypeScript }, root); + var serializeFunction = root.FindChildByName($"deserializeInto{parentClass.Name.ToFirstCharacterUpperCase()}"); + writer.Write(serializeFunction); + var result = tw.ToString(); + Assert.Contains("// eslint-disable", result); + Assert.Contains("// tslint:disable", result); + } + [Fact] + public async Task WritesAutoGenerationEnd() + { + var parentClass = TestHelper.CreateModelClass(root, "parentClass", true); + TestHelper.AddSerializationPropertiesToModelClass(parentClass); + await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.TypeScript }, root); + var serializeFunction = root.FindChildByName($"deserializeInto{parentClass.Name.ToFirstCharacterUpperCase()}"); + writer.Write(serializeFunction); + var result = tw.ToString(); + Assert.DoesNotContain("// eslint-enable", result); //written by code end block writer + Assert.DoesNotContain("// tslint:enable", result); + } + [Fact] public async Task WritesModelFactoryBody() { diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeInterfaceDeclarationWriterTests .cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeInterfaceDeclarationWriterTests .cs index f22a8500d5..4250c495ec 100644 --- a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeInterfaceDeclarationWriterTests .cs +++ b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeInterfaceDeclarationWriterTests .cs @@ -3,71 +3,77 @@ using Kiota.Builder.CodeDOM; using Xunit; -namespace Kiota.Builder.Writers.TypeScript.Tests +namespace Kiota.Builder.Writers.TypeScript.Tests; +public class CodeInterfaceDeclaraterWriterTests : IDisposable { - public class CodeInterfaceDeclaraterWriterTests : IDisposable - { - private const string DefaultPath = "./"; - private const string DefaultName = "name"; - private readonly StringWriter tw; - private readonly LanguageWriter writer; - private readonly CodeInterface parentInterface; + private const string DefaultPath = "./"; + private const string DefaultName = "name"; + private readonly StringWriter tw; + private readonly LanguageWriter writer; + private readonly CodeInterface parentInterface; - public CodeInterfaceDeclaraterWriterTests() - { - writer = LanguageWriter.GetLanguageWriter(GenerationLanguage.TypeScript, DefaultPath, DefaultName); - tw = new StringWriter(); - writer.SetTextWriter(tw); - var root = CodeNamespace.InitRootNamespace(); - var ns = root.AddNamespace("graphtests.models"); - parentInterface = new CodeInterface() - { - Name = "parent" - }; - ns.AddInterface(parentInterface); - } - public void Dispose() - { - tw?.Dispose(); - GC.SuppressFinalize(this); - } - [Fact] - public void WritesSimpleDeclaration() + public CodeInterfaceDeclaraterWriterTests() + { + writer = LanguageWriter.GetLanguageWriter(GenerationLanguage.TypeScript, DefaultPath, DefaultName); + tw = new StringWriter(); + writer.SetTextWriter(tw); + var root = CodeNamespace.InitRootNamespace(); + var ns = root.AddNamespace("graphtests.models"); + parentInterface = new CodeInterface() { - writer.Write(parentInterface.StartBlock); - var result = tw.ToString(); - Assert.Contains("export interface", result); - } + Name = "parent" + }; + ns.AddInterface(parentInterface); + } + public void Dispose() + { + tw?.Dispose(); + GC.SuppressFinalize(this); + } + [Fact] + public void WritesAutoGenerationStart() + { + writer.Write(parentInterface.StartBlock); + var result = tw.ToString(); + Assert.Contains("// eslint-disable", result); + Assert.Contains("// tslint:disable", result); + } + [Fact] + public void WritesSimpleDeclaration() + { + writer.Write(parentInterface.StartBlock); + var result = tw.ToString(); + Assert.Contains("export interface", result); + } - [Fact] - public void WritesInheritance() - { + [Fact] + public void WritesInheritance() + { - parentInterface.StartBlock.AddImplements(new CodeType() - { - Name = "someInterface" - }); - writer.Write(parentInterface.StartBlock); - var result = tw.ToString(); - Assert.Contains("extends", result); - } - [Fact] - public void WritesImports() + parentInterface.StartBlock.AddImplements(new CodeType() + { + Name = "someInterface" + }); + writer.Write(parentInterface.StartBlock); + var result = tw.ToString(); + Assert.Contains("extends", result); + } + [Fact] + public void WritesImports() + { + parentInterface.StartBlock.AddUsings(new CodeUsing { - parentInterface.StartBlock.AddUsings(new CodeUsing + Name = "Objects", + Declaration = new() { - Name = "Objects", - Declaration = new() - { - Name = "util", - IsExternal = true, - } - }); - writer.Write(parentInterface.StartBlock); - var result = tw.ToString(); - Assert.Contains("import", result); - Assert.Contains("from", result); - Assert.Contains("'util'", result); - } + Name = "util", + IsExternal = true, + } + }); + writer.Write(parentInterface.StartBlock); + var result = tw.ToString(); + Assert.Contains("import", result); + Assert.Contains("from", result); + Assert.Contains("'util'", result); } } diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodePropertyWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodePropertyWriterTests.cs index 9d9e2ef90e..8961fc4114 100644 --- a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodePropertyWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodePropertyWriterTests.cs @@ -75,7 +75,8 @@ public void WritesCustomProperty() property.Kind = CodePropertyKind.Custom; writer.Write(property); var result = tw.ToString(); - Assert.Contains($"{PropertyName}?: {TypeName} | undefined", result); + Assert.Contains($"{PropertyName}?: {TypeName}", result); + Assert.DoesNotContain("| undefined", result); // redundant with ? } [Fact] public void WritesFlagEnums()