diff --git a/CHANGELOG.md b/CHANGELOG.md index d48dbe6c89..be1ce6bb4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,10 +14,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Fixed a bug where multiple Visual Studio Code instances would make the extension install/update fail. [#3686](https://github.com/microsoft/kiota/issues/3686) +- Fixed a bug where models properties named "additionalData" or "backingstore" would be ignored. [#4224](https://github.com/microsoft/kiota/issues/4224) - PREVIEW: Renamed the config commands to workspace. [#4310](https://github.com/microsoft/kiota/issues/4310) - PREVIEW: Moved preview configuration files to the .kiota directory. [#4310](https://github.com/microsoft/kiota/issues/4310) - PREVIEW: Moved the copy descriptions to dedicated folders. [#4310](https://github.com/microsoft/kiota/issues/4310) - PREVIEW: Renamed the config to workspace file. [#4310](https://github.com/microsoft/kiota/issues/4310) +- Fixed a bug where TypeScript generation would consider boolean argument as empty when false. [#4103](https://github.com/microsoft/kiota/issues/4103) - Changed Csharp code generation to put braces on new lines (where it makes sense). [#4347](https://github.com/microsoft/kiota/issues/4347) - TypeScript is now a preview language! diff --git a/src/Kiota.Builder/CodeDOM/CodeClass.cs b/src/Kiota.Builder/CodeDOM/CodeClass.cs index a46e5c1b79..41a41061c2 100644 --- a/src/Kiota.Builder/CodeDOM/CodeClass.cs +++ b/src/Kiota.Builder/CodeDOM/CodeClass.cs @@ -167,7 +167,7 @@ private string ResolveUniquePropertyName(string name) ArgumentException.ThrowIfNullOrEmpty(serializationName); if (BaseClass is CodeClass currentParentClass) - if (currentParentClass.FindPropertyByWireName(serializationName) is CodeProperty currentProperty && !currentProperty.ExistsInBaseType) + if (currentParentClass.FindPropertyByWireName(serializationName) is CodeProperty currentProperty && !currentProperty.ExistsInBaseType && currentProperty.Kind is not CodePropertyKind.AdditionalData or CodePropertyKind.BackingStore) return currentProperty; else return currentParentClass.GetOriginalPropertyDefinedFromBaseType(serializationName); diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs index c5b809c950..0e54393520 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs @@ -259,7 +259,7 @@ private static string GetDefaultValueLiteralForProperty(CodeProperty codePropert return $"{enumDefinition.CodeEnumObject.Name.ToFirstCharacterUpperCase()}.{codeProperty.DefaultValue.Trim('"').CleanupSymbolName().ToFirstCharacterUpperCase()}"; return codeProperty.DefaultValue; } - private static void WriteDefensiveStatements(CodeMethod codeElement, LanguageWriter writer) + private void WriteDefensiveStatements(CodeMethod codeElement, LanguageWriter writer) { if (codeElement.IsOfKind(CodeMethodKind.Setter)) return; @@ -271,7 +271,8 @@ private static void WriteDefensiveStatements(CodeMethod codeElement, LanguageWri .OrderBy(static x => x.Name, StringComparer.OrdinalIgnoreCase)) { var parameterName = parameter.Name.ToFirstCharacterLowerCase(); - writer.WriteLine($"if(!{parameterName}) throw new Error(\"{parameterName} cannot be undefined\");"); + if (!"boolean".Equals(conventions.TranslateType(parameter.Type), StringComparison.OrdinalIgnoreCase)) + writer.WriteLine($"if(!{parameterName}) throw new Error(\"{parameterName} cannot be undefined\");"); } } private string GetDeserializationMethodName(CodeTypeBase propType, CodeFunction codeFunction) diff --git a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs index 99ea0c4769..69d1eb4ca7 100644 --- a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs +++ b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs @@ -697,6 +697,83 @@ public async Task TrimsInheritanceUnusedModels() Assert.Null(modelsNS.FindChildByName("AuditEvent", false)); //unused type } [Fact] + public async Task DisambiguatesReservedProperties() + { + var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + await using var fs = await GetDocumentStream(@"openapi: 3.0.1 +info: + title: OData Service for namespace microsoft.graph + description: This OData service is located at https://graph.microsoft.com/v1.0 + version: v1.0 + x-ms-generated-by: + toolName: Microsoft.OpenApi.OData + toolVersion: 1.0.9.0 +servers: + - url: https://graph.microsoft.com/v1.0 +paths: + '/security/alerts_v2/{alert-id}': + get: + responses: + 200: + content: + application/json: + schema: + $ref: '#/components/schemas/microsoft.graph.alert' +components: + schemas: + microsoft.graph.entity: + title: entity + required: + - '@odata.type' + type: object + properties: + id: + type: string + '@odata.type': + type: string + microsoft.graph.dictionary: + title: dictionary + required: + - '@odata.type' + type: object + properties: + '@odata.type': + type: string + microsoft.graph.alert: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - title: alert + required: + - '@odata.type' + type: object + properties: + actorDisplayName: + type: string + nullable: true + additionalData: + anyOf: + - $ref: '#/components/schemas/microsoft.graph.dictionary' + - type: object + nullable: true"); + var mockLogger = new Mock>(); + var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "Graph", OpenAPIFilePath = tempFilePath }, _httpClient); + var document = await builder.CreateOpenApiDocumentAsync(fs); + var node = builder.CreateUriSpace(document); + var codeModel = builder.CreateSourceModel(node); + var modelsNS = codeModel.FindNamespaceByName("ApiSdk.models.microsoft.graph"); + Assert.NotNull(modelsNS); + var entityClass = modelsNS.FindChildByName("Entity", false); + Assert.NotNull(entityClass); + var additionalDataProperty = entityClass.FindChildByName("AdditionalData", false); + Assert.NotNull(additionalDataProperty); + Assert.True(additionalDataProperty.Kind is CodePropertyKind.AdditionalData); + var alertClass = modelsNS.FindChildByName("Alert", false); + Assert.NotNull(alertClass); + var additionalDataEscapedProperty = alertClass.FindChildByName("AdditionalDataProperty", false); + Assert.NotNull(additionalDataEscapedProperty); + Assert.True(additionalDataEscapedProperty.Kind is CodePropertyKind.Custom); + } + [Fact] public async Task TrimsInheritanceUnusedModelsWithUnion() { var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs index 8855644e50..a22dec13c7 100644 --- a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs @@ -717,6 +717,63 @@ public void WritesDeprecationInformationFromBuilder() var result = tw.ToString(); Assert.Contains("This method is obsolete. Use NewAwesomeMethod instead.", result); } + [Fact] + public void WritesDefensiveStatements() + { + var parentClass = root.AddClass(new CodeClass + { + Name = "ODataError", + Kind = CodeClassKind.Model, + }).First(); + parentClass.DiscriminatorInformation.DiscriminatorPropertyName = "@odata.type"; + parentClass.DiscriminatorInformation.AddDiscriminatorMapping("string", new CodeType() { Name = "string" }); + var method = TestHelper.CreateMethod(parentClass, MethodName, ReturnTypeName); + method.AddParameter(new CodeParameter + { + Name = "param1", + Type = new CodeType() + { + Name = "string", + IsNullable = false, + }, + }); + method.Kind = CodeMethodKind.Factory; + method.IsStatic = true; + method.Name = "NewAwesomeMethod";// new method replacement + var function = new CodeFunction(method); + root.TryAddCodeFile("foo", function); + writer.Write(function); + var result = tw.ToString(); + Assert.Contains("cannot be undefined", result); + } + [Fact] + public void DoesNotWriteDefensiveStatementsForBooleanParameters() + { + var parentClass = root.AddClass(new CodeClass + { + Name = "ODataError", + Kind = CodeClassKind.Model, + }).First(); + var method = TestHelper.CreateMethod(parentClass, MethodName, ReturnTypeName); + method.AddParameter(new CodeParameter + { + Name = "param1", + Type = new CodeType() + { + Name = "boolean", + IsNullable = false, + }, + Optional = false, + }); + method.Kind = CodeMethodKind.Factory; + method.IsStatic = true; + method.Name = "NewAwesomeMethod";// new method replacement + var function = new CodeFunction(method); + root.TryAddCodeFile("foo", function); + writer.Write(function); + var result = tw.ToString(); + Assert.DoesNotContain("cannot be undefined", result); + } private const string MethodDescription = "some description"; private const string ParamDescription = "some parameter description"; private const string ParamName = "paramName";