diff --git a/src/Kiota.Builder/Configuration/LanguagesInformation.cs b/src/Kiota.Builder/Configuration/LanguagesInformation.cs index 5dcb41dc59..a80f718faf 100644 --- a/src/Kiota.Builder/Configuration/LanguagesInformation.cs +++ b/src/Kiota.Builder/Configuration/LanguagesInformation.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.OpenApi.Any; +using System.Text.Json.Nodes; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -9,23 +9,14 @@ namespace Kiota.Builder.Configuration; public class LanguagesInformation : Dictionary, IOpenApiSerializable, ICloneable { - public void SerializeAsV2(IOpenApiWriter writer) => SerializeAsV3(writer); - public void SerializeAsV3(IOpenApiWriter writer) + public void SerializeAsV2(IOpenApiWriter writer) => SerializeAsV31(writer); + public void SerializeAsV3(IOpenApiWriter writer) => SerializeAsV31(writer); + public static LanguagesInformation Parse(JsonObject jsonNode) { - ArgumentNullException.ThrowIfNull(writer); - writer.WriteStartObject(); - foreach (var entry in this.OrderBy(static x => x.Key, StringComparer.OrdinalIgnoreCase)) - { - writer.WriteRequiredObject(entry.Key, entry.Value, (w, x) => x.SerializeAsV3(w)); - } - writer.WriteEndObject(); - } - public static LanguagesInformation Parse(IOpenApiAny source) - { - if (source is not OpenApiObject rawObject) throw new ArgumentOutOfRangeException(nameof(source)); var extension = new LanguagesInformation(); - foreach (var property in rawObject) - extension.Add(property.Key, LanguageInformation.Parse(property.Value)); + foreach (var property in jsonNode.Where(static property => property.Value is JsonObject)) + extension.Add(property.Key, LanguageInformation.Parse(property.Value!)); + return extension; } @@ -36,4 +27,15 @@ public object Clone() result.Add(entry.Key, entry.Value);// records don't need to be cloned as they are immutable return result; } + + public void SerializeAsV31(IOpenApiWriter writer) + { + ArgumentNullException.ThrowIfNull(writer); + writer.WriteStartObject(); + foreach (var entry in this.OrderBy(static x => x.Key, StringComparer.OrdinalIgnoreCase)) + { + writer.WriteRequiredObject(entry.Key, entry.Value, (w, x) => x.SerializeAsV3(w)); + } + writer.WriteEndObject(); + } } diff --git a/src/Kiota.Builder/Extensions/OpenApiDeprecationExtensionExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiDeprecationExtensionExtensions.cs index 75a2b5921d..8d29cd92ba 100644 --- a/src/Kiota.Builder/Extensions/OpenApiDeprecationExtensionExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiDeprecationExtensionExtensions.cs @@ -24,15 +24,15 @@ internal static DeprecationInformation GetDeprecationInformation(this OpenApiPar return deprecatedValue.ToDeprecationInformation(); else if (parameter.Schema != null && !parameter.Schema.IsReferencedSchema() && parameter.Schema.Deprecated) return parameter.Schema.GetDeprecationInformation(); - else if (parameter.Content.Values.Select(static x => x.Schema).Where(static x => x != null && !x.IsReferencedSchema() && x.Deprecated).Select(static x => x.GetDeprecationInformation()).FirstOrDefault(static x => x.IsDeprecated) is DeprecationInformation contentDeprecationInformation) + else if (parameter.Content.Values.Select(static x => x.Schema).Where(static x => x != null && !x.IsReferencedSchema() && x.Deprecated).Select(static x => x!.GetDeprecationInformation()).FirstOrDefault(static x => x.IsDeprecated) is DeprecationInformation contentDeprecationInformation) return contentDeprecationInformation; return new(null, null, null, null, parameter.Deprecated); } internal static DeprecationInformation GetDeprecationInformation(this OpenApiOperation operation) { - if (operation.Deprecated && operation.Extensions.TryGetValue(OpenApiDeprecationExtension.Name, out var deprecatedExtension) && deprecatedExtension is OpenApiDeprecationExtension deprecatedValue) + if (operation.Deprecated && operation.Extensions is not null && operation.Extensions.TryGetValue(OpenApiDeprecationExtension.Name, out var deprecatedExtension) && deprecatedExtension is OpenApiDeprecationExtension deprecatedValue) return deprecatedValue.ToDeprecationInformation(); - else if (operation.Responses.Values + else if (operation.Responses?.Values .SelectMany(static x => x.Content.Values) .Select(static x => x?.Schema) .OfType() diff --git a/src/Kiota.Builder/Extensions/OpenApiDocumentExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiDocumentExtensions.cs index dc46ca6807..a655a79f12 100644 --- a/src/Kiota.Builder/Extensions/OpenApiDocumentExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiDocumentExtensions.cs @@ -31,7 +31,7 @@ internal static void InitializeInheritanceIndex(this OpenApiDocument openApiDocu { ArgumentNullException.ThrowIfNull(openApiDocument); var candidateUrl = openApiDocument.Servers - .GroupBy(static x => x, new OpenApiServerComparer()) //group by protocol relative urls + ?.GroupBy(static x => x, new OpenApiServerComparer()) //group by protocol relative urls .FirstOrDefault() ?.OrderByDescending(static x => x.Url, StringComparer.OrdinalIgnoreCase) // prefer https over http ?.FirstOrDefault() diff --git a/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs index 2ca1fd3009..23c7659f88 100644 --- a/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs @@ -30,6 +30,7 @@ private static string vendorSpecificCleanup(string input) } internal static IEnumerable GetResponseSchemas(this OpenApiOperation operation, HashSet successCodesToUse, StructuredMimeTypesCollection structuredMimeTypes) { + if (operation.Responses is null) return []; // Return Schema that represents all the possible success responses! return operation.Responses.Where(r => successCodesToUse.Contains(r.Key)) .OrderBy(static x => x.Key, StringComparer.OrdinalIgnoreCase) @@ -67,7 +68,7 @@ internal static IEnumerable GetValidSchemas(this IDictionary (Key: c.Key.Split(';', StringSplitOptions.RemoveEmptyEntries)[0], c.Value)) .Where(c => structuredMimeTypes.Contains(c.Key) || structuredMimeTypes.Contains(vendorSpecificCleanup(c.Key))) .Select(static co => co.Value.Schema) - .Where(static s => s is not null); + .OfType(); } internal static OpenApiSchema? GetResponseSchema(this OpenApiResponse response, StructuredMimeTypesCollection structuredMimeTypes) { diff --git a/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs index cec1a3cf2b..8c814b0e07 100644 --- a/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs @@ -2,7 +2,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; -using Microsoft.OpenApi.Any; +using System.Text.Json; using Microsoft.OpenApi.Models; namespace Kiota.Builder.Extensions; @@ -53,7 +53,7 @@ public static bool IsReferencedSchema(this OpenApiSchema schema) public static bool IsArray(this OpenApiSchema? schema) { - return "array".Equals(schema?.Type, StringComparison.OrdinalIgnoreCase) && schema.Items != null && + return schema is { Type: JsonSchemaType.Array or (JsonSchemaType.Array | JsonSchemaType.Null) } && schema.Items is not null && (schema.Items.IsComposedEnum() || schema.Items.IsEnum() || schema.Items.IsSemanticallyMeaningful() || @@ -62,7 +62,7 @@ public static bool IsArray(this OpenApiSchema? schema) public static bool IsObjectType(this OpenApiSchema? schema) { - return "object".Equals(schema?.Type, StringComparison.OrdinalIgnoreCase); + return schema is { Type: JsonSchemaType.Object or (JsonSchemaType.Object | JsonSchemaType.Null) }; } public static bool HasAnyProperty(this OpenApiSchema? schema) { @@ -80,7 +80,7 @@ public static bool IsInherited(this OpenApiSchema? schema) var meaningfulMemberSchemas = schema.AllOf.FlattenSchemaIfRequired(static x => x.AllOf) .Where(static x => x.IsSemanticallyMeaningful(ignoreEnums: true, ignoreArrays: true, ignoreType: true)) // the next line ensures the meaningful schema are objects as it won't make sense inheriting from a primitive despite it being meaningful. - .Where(static x => string.IsNullOrEmpty(x.Reference?.Id) || string.IsNullOrEmpty(x.Type) || "object".Equals(x.Type, StringComparison.OrdinalIgnoreCase)) + .Where(static x => string.IsNullOrEmpty(x.Reference?.Id) || x.Type is null || !x.Type.HasValue || (x.Type.Value & JsonSchemaType.Object) is JsonSchemaType.Object) .ToArray(); var isRootSchemaMeaningful = schema.IsSemanticallyMeaningful(ignoreEnums: true, ignoreArrays: true, ignoreType: true); return meaningfulMemberSchemas.Count(static x => !string.IsNullOrEmpty(x.Reference?.Id)) == 1 && @@ -162,45 +162,48 @@ public static bool IsExclusiveUnion(this OpenApiSchema? schema, uint exclusiveMi return schema?.OneOf?.Count(static x => IsSemanticallyMeaningful(x, true)) > exclusiveMinimumNumberOfEntries; // so we don't consider one of object/nullable as a union type } - private static readonly HashSet oDataTypes = new(StringComparer.OrdinalIgnoreCase) { - "number", - "integer", - }; + private static readonly HashSet oDataTypes = [ + JsonSchemaType.Number, + JsonSchemaType.Integer, + ]; + private static readonly Func isODataType = static x => x.Type is not null && oDataTypes.Contains(x.Type.Value); + private static readonly Func isStringType = static x => x is { Type: JsonSchemaType.String or (JsonSchemaType.String | JsonSchemaType.Null) }; private static bool IsODataPrimitiveTypeBackwardCompatible(this OpenApiSchema schema) { return schema.IsExclusiveUnion() && schema.OneOf.Count == 3 && schema.OneOf.Count(static x => x.Enum?.Any() ?? false) == 1 && - schema.OneOf.Count(static x => oDataTypes.Contains(x.Type)) == 1 && - schema.OneOf.Count(static x => "string".Equals(x.Type, StringComparison.OrdinalIgnoreCase)) == 1 + schema.OneOf.Count(isODataType) == 1 && + schema.OneOf.Count(isStringType) == 1 || schema.IsInclusiveUnion() && schema.AnyOf.Count == 3 && schema.AnyOf.Count(static x => x.Enum?.Any() ?? false) == 1 && - schema.AnyOf.Count(static x => oDataTypes.Contains(x.Type)) == 1 && - schema.AnyOf.Count(static x => "string".Equals(x.Type, StringComparison.OrdinalIgnoreCase)) == 1; + schema.AnyOf.Count(isODataType) == 1 && + schema.AnyOf.Count(isStringType) == 1; } public static bool IsODataPrimitiveType(this OpenApiSchema schema) { return schema.IsExclusiveUnion() && schema.OneOf.Count == 3 && - schema.OneOf.Count(static x => "string".Equals(x.Type, StringComparison.OrdinalIgnoreCase) && (x.Enum?.Any() ?? false)) == 1 && - schema.OneOf.Count(static x => oDataTypes.Contains(x.Type)) == 1 && - schema.OneOf.Count(static x => "string".Equals(x.Type, StringComparison.OrdinalIgnoreCase)) == 2 + schema.OneOf.Count(static x => isStringType(x) && (x.Enum?.Any() ?? false)) == 1 && + schema.OneOf.Count(isODataType) == 1 && + schema.OneOf.Count(isStringType) == 2 || schema.IsInclusiveUnion() && schema.AnyOf.Count == 3 && - schema.AnyOf.Count(static x => "string".Equals(x.Type, StringComparison.OrdinalIgnoreCase) && (x.Enum?.Any() ?? false)) == 1 && - schema.AnyOf.Count(static x => oDataTypes.Contains(x.Type)) == 1 && - schema.AnyOf.Count(static x => "string".Equals(x.Type, StringComparison.OrdinalIgnoreCase)) == 2 + schema.AnyOf.Count(static x => isStringType(x) && (x.Enum?.Any() ?? false)) == 1 && + schema.AnyOf.Count(isODataType) == 1 && + schema.AnyOf.Count(isStringType) == 2 || schema.IsODataPrimitiveTypeBackwardCompatible(); } public static bool IsEnum(this OpenApiSchema schema) { if (schema is null) return false; - return schema.Enum.OfType().Any(static x => !string.IsNullOrEmpty(x.Value)) && - (string.IsNullOrEmpty(schema.Type) || "string".Equals(schema.Type, StringComparison.OrdinalIgnoreCase)); // number and boolean enums are not supported + return schema.Enum.Any(static x => x.GetValueKind() is JsonValueKind.String && + x.GetValue() is string value && + !string.IsNullOrEmpty(value)); // number and boolean enums are not supported } public static bool IsComposedEnum(this OpenApiSchema schema) { @@ -214,8 +217,8 @@ public static bool IsSemanticallyMeaningful(this OpenApiSchema schema, bool igno return schema.HasAnyProperty() || (!ignoreEnums && schema.Enum is { Count: > 0 }) || (!ignoreArrays && schema.Items != null) || - (!ignoreType && !string.IsNullOrEmpty(schema.Type) && - ((ignoreNullableObjects && !"object".Equals(schema.Type, StringComparison.OrdinalIgnoreCase)) || + (!ignoreType && schema.Type is not null && + ((ignoreNullableObjects && !schema.IsObjectType()) || !ignoreNullableObjects)) || !string.IsNullOrEmpty(schema.Format) || !string.IsNullOrEmpty(schema.Reference?.Id); @@ -306,7 +309,7 @@ internal static string GetDiscriminatorPropertyName(this OpenApiSchema schema, H internal static IEnumerable> GetDiscriminatorMappings(this OpenApiSchema schema, ConcurrentDictionary> inheritanceIndex) { if (schema == null) - return Enumerable.Empty>(); + return []; if (!(schema.Discriminator?.Mapping?.Any() ?? false)) if (schema.OneOf.Any()) return schema.OneOf.SelectMany(x => GetDiscriminatorMappings(x, inheritanceIndex)); @@ -319,9 +322,9 @@ internal static IEnumerable> GetDiscriminatorMappin return GetAllInheritanceSchemaReferences(schema.Reference.Id, inheritanceIndex) .Where(static x => !string.IsNullOrEmpty(x)) .Select(x => KeyValuePair.Create(x, x)) - .Union(new[] { KeyValuePair.Create(schema.Reference.Id, schema.Reference.Id) }); + .Union([KeyValuePair.Create(schema.Reference.Id, schema.Reference.Id)]); else - return Enumerable.Empty>(); + return []; return schema.Discriminator .Mapping; diff --git a/src/Kiota.Builder/Extensions/OpenApiSettingsExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiSettingsExtensions.cs index 118ac47698..6546b601cb 100644 --- a/src/Kiota.Builder/Extensions/OpenApiSettingsExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiSettingsExtensions.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using Kiota.Builder.OpenApiExtensions; -using Microsoft.OpenApi.Readers; +using Microsoft.OpenApi.Reader; namespace Kiota.Builder.Extensions; public static class OpenApiSettingsExtensions diff --git a/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs index a49b82968a..98e4e8a6af 100644 --- a/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs @@ -69,7 +69,7 @@ internal static string CleanupParametersFromPath(string pathSegment) private static IEnumerable GetParametersForPathItem(OpenApiPathItem pathItem, string nodeSegment) { return pathItem.Parameters - .Union(pathItem.Operations.SelectMany(static x => x.Value.Parameters)) + .Union(pathItem.Operations.SelectMany(static x => x.Value.Parameters ?? Enumerable.Empty())) .Where(static x => x.In == ParameterLocation.Path) .Where(x => nodeSegment.Contains($"{{{x.Name}}}", StringComparison.OrdinalIgnoreCase)); } @@ -193,7 +193,7 @@ public static bool HasRequiredQueryParametersAcrossOperations(this OpenApiUrlTre if (!currentNode.PathItems.TryGetValue(Constants.DefaultOpenApiLabel, out var pathItem)) return false; - var operationQueryParameters = pathItem.Operations.SelectMany(static x => x.Value.Parameters); + var operationQueryParameters = pathItem.Operations.SelectMany(static x => x.Value.Parameters ?? Enumerable.Empty()); return operationQueryParameters.Union(pathItem.Parameters).Where(static x => x.In == ParameterLocation.Query) .Any(static x => x.Required); } @@ -207,9 +207,9 @@ public static string GetUrlTemplate(this OpenApiUrlTreeNode currentNode, Operati var pathItem = currentNode.PathItems[Constants.DefaultOpenApiLabel]; var operationQueryParameters = (operationType, pathItem.Operations.Any()) switch { - (OperationType ot, _) when pathItem.Operations.TryGetValue(ot, out var operation) => operation.Parameters, - (null, true) => pathItem.Operations.SelectMany(static x => x.Value.Parameters).Where(static x => x.In == ParameterLocation.Query), - _ => Enumerable.Empty(), + (OperationType ot, _) when pathItem.Operations.TryGetValue(ot, out var operation) && operation.Parameters is not null => operation.Parameters, + (null, true) => pathItem.Operations.SelectMany(static x => x.Value.Parameters ?? Enumerable.Empty()).Where(static x => x.In == ParameterLocation.Query), + _ => [], }; var parameters = pathItem.Parameters .Union(operationQueryParameters) @@ -234,7 +234,7 @@ public static string GetUrlTemplate(this OpenApiUrlTreeNode currentNode, Operati } var pathReservedPathParametersIds = currentNode.PathItems.TryGetValue(Constants.DefaultOpenApiLabel, out var pItem) ? pItem.Parameters - .Union(pItem.Operations.SelectMany(static x => x.Value.Parameters)) + .Union(pItem.Operations.SelectMany(static x => x.Value.Parameters ?? Enumerable.Empty())) .Where(static x => x.In == ParameterLocation.Path && x.Extensions.TryGetValue(OpenApiReservedParameterExtension.Name, out var ext) && ext is OpenApiReservedParameterExtension reserved && reserved.IsReserved.HasValue && reserved.IsReserved.Value) .Select(static x => x.Name) .ToHashSet(StringComparer.OrdinalIgnoreCase) : @@ -356,7 +356,7 @@ private static void ReplaceParameterInPathForAllChildNodes(OpenApiUrlTreeNode no if (node.PathItems.TryGetValue(Constants.DefaultOpenApiLabel, out var pathItem)) { foreach (var pathParameter in pathItem.Parameters - .Union(pathItem.Operations.SelectMany(static x => x.Value.Parameters)) + .Union(pathItem.Operations.SelectMany(static x => x.Value.Parameters ?? Enumerable.Empty())) .Where(x => x.In == ParameterLocation.Path && oldName.Equals(x.Name, StringComparison.Ordinal))) { pathParameter.Name = newParameterName; @@ -386,7 +386,7 @@ private static void CopyNodeIntoOtherNode(OpenApiUrlTreeNode source, OpenApiUrlT pathItem .Value .Operations - .SelectMany(static x => x.Value.Parameters) + .SelectMany(static x => x.Value.Parameters ?? Enumerable.Empty()) .Where(x => x.In == ParameterLocation.Path && pathParameterNameToReplace.Equals(x.Name, StringComparison.Ordinal)) )) { diff --git a/src/Kiota.Builder/Kiota.Builder.csproj b/src/Kiota.Builder/Kiota.Builder.csproj index e3d04ad2f2..6fcc1b6710 100644 --- a/src/Kiota.Builder/Kiota.Builder.csproj +++ b/src/Kiota.Builder/Kiota.Builder.csproj @@ -44,9 +44,9 @@ - - - + + + diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs index b4466a5bf0..8a47e6a4d9 100644 --- a/src/Kiota.Builder/KiotaBuilder.cs +++ b/src/Kiota.Builder/KiotaBuilder.cs @@ -8,7 +8,10 @@ using System.Linq; using System.Net.Http; using System.Runtime.CompilerServices; +using System.Security.Cryptography; using System.Text; +using System.Text.Json; +using System.Text.Json.Nodes; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; @@ -31,6 +34,7 @@ using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.ApiManifest; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.MicrosoftExtensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; @@ -224,7 +228,7 @@ private void UpdateConfigurationFromOpenApiDocument() } private LanguagesInformation? GetLanguagesInformationInternal() { - if (openApiDocument == null) + if (openApiDocument is null || openApiDocument.Extensions is null) return null; if (openApiDocument.Extensions.TryGetValue(OpenApiKiotaExtension.Name, out var ext) && ext is OpenApiKiotaExtension kiotaExt) return kiotaExt.LanguagesInformation; @@ -535,18 +539,18 @@ public CodeNamespace CreateSourceModel(OpenApiUrlTreeNode? root) var codeNamespace = rootNamespace.AddNamespace(config.ClientNamespaceName); modelsNamespace = rootNamespace.AddNamespace(config.ModelsNamespaceName); InitializeInheritanceIndex(); - StopLogAndReset(stopwatch, $"{nameof(InitializeInheritanceIndex)}"); + StopLogAndReset(stopwatch, nameof(InitializeInheritanceIndex)); if (root != null) { CreateRequestBuilderClass(codeNamespace, root, root); - StopLogAndReset(stopwatch, $"{nameof(CreateRequestBuilderClass)}"); + StopLogAndReset(stopwatch, nameof(CreateRequestBuilderClass)); stopwatch.Start(); MapTypeDefinitions(codeNamespace); - StopLogAndReset(stopwatch, $"{nameof(MapTypeDefinitions)}"); + StopLogAndReset(stopwatch, nameof(MapTypeDefinitions)); TrimInheritedModels(); - StopLogAndReset(stopwatch, $"{nameof(TrimInheritedModels)}"); + StopLogAndReset(stopwatch, nameof(TrimInheritedModels)); CleanUpInternalState(); - StopLogAndReset(stopwatch, $"{nameof(CleanUpInternalState)}"); + StopLogAndReset(stopwatch, nameof(CleanUpInternalState)); logger.LogTrace("{Timestamp}ms: Created source model with {Count} classes", stopwatch.ElapsedMilliseconds, codeNamespace.GetChildElements(true).Count()); } @@ -1011,7 +1015,7 @@ private CodeParameter GetIndexerParameter(OpenApiUrlTreeNode currentNode, OpenAp var pathItems = GetPathItems(currentNode); var parameter = pathItems.TryGetValue(Constants.DefaultOpenApiLabel, out var pathItem) ? pathItem.Parameters .Select(static x => new { Parameter = x, IsPathParameter = true }) - .Union(pathItems[Constants.DefaultOpenApiLabel].Operations.SelectMany(static x => x.Value.Parameters).Select(static x => new { Parameter = x, IsPathParameter = false })) + .Union(pathItems[Constants.DefaultOpenApiLabel].Operations.SelectMany(static x => x.Value.Parameters ?? []).Select(static x => new { Parameter = x, IsPathParameter = false })) .OrderBy(static x => x.IsPathParameter) .Select(static x => x.Parameter) .FirstOrDefault(x => x.Name.Equals(parameterName, StringComparison.OrdinalIgnoreCase) && x.In == ParameterLocation.Path) : @@ -1078,7 +1082,7 @@ private CodeIndexer[] CreateIndexer(string childIdentifier, string childType, Co result.Add(backCompatibleValue); } - return result.ToArray(); + return [.. result]; } private static readonly StructuralPropertiesReservedNameProvider structuralPropertiesReservedNameProvider = new(); @@ -1088,6 +1092,8 @@ private CodeIndexer[] CreateIndexer(string childIdentifier, string childType, Co if (structuralPropertiesReservedNameProvider.ReservedNames.Contains(propertyName)) propertyName += "Property"; var resultType = existingType ?? GetPrimitiveType(propertySchema, childType); + if ((propertySchema?.Items?.IsEnum() ?? false) && resultType is CodeType codeType) + codeType.Name = childType; if (resultType == null) return null; var prop = new CodeProperty { @@ -1112,9 +1118,10 @@ openApiExtension is OpenApiPrimaryErrorMessageExtension primaryErrorMessageExten !propertyName.Equals(childIdentifier, StringComparison.Ordinal)) prop.SerializationName = childIdentifier; if (kind == CodePropertyKind.Custom && - propertySchema?.Default is OpenApiString stringDefaultValue && - !string.IsNullOrEmpty(stringDefaultValue.Value)) - prop.DefaultValue = $"\"{stringDefaultValue.Value}\""; + propertySchema?.Default is JsonValue stringDefaultJsonValue && + stringDefaultJsonValue.TryGetValue(out var stringDefaultValue) && + !string.IsNullOrEmpty(stringDefaultValue)) + prop.DefaultValue = $"\"{stringDefaultValue}\""; if (existingType == null) { @@ -1123,58 +1130,41 @@ openApiExtension is OpenApiPrimaryErrorMessageExtension primaryErrorMessageExten } return prop; } - private static readonly HashSet typeNamesToSkip = new(StringComparer.OrdinalIgnoreCase) { "object", "array" }; + private static readonly HashSet typeNamesToSkip = [JsonSchemaType.Object, JsonSchemaType.Array]; private static CodeType? GetPrimitiveType(OpenApiSchema? typeSchema, string? childType = default) { - var typeNames = new List { typeSchema?.Items?.Type, childType, typeSchema?.Type }; + var typeNames = new List { typeSchema?.Items?.Type, typeSchema?.Type }; if (typeSchema?.AnyOf?.Any() ?? false) typeNames.AddRange(typeSchema.AnyOf.Select(x => x.Type)); // double is sometimes an anyof string, number and enum if (typeSchema?.OneOf?.Any() ?? false) typeNames.AddRange(typeSchema.OneOf.Select(x => x.Type)); // double is sometimes an oneof string, number and enum // first value that's not null, and not "object" for primitive collections, the items type matters - var typeName = typeNames.Find(static x => !string.IsNullOrEmpty(x) && !typeNamesToSkip.Contains(x)); - - var isExternal = false; - if (typeSchema?.Items?.IsEnum() ?? false) - typeName = childType; - else - { - var format = typeSchema?.Format ?? typeSchema?.Items?.Format; - var primitiveTypeName = (typeName?.ToLowerInvariant(), format?.ToLowerInvariant()) switch - { - ("string", "base64url") => "base64url", - ("file", _) => "binary", - ("string", "duration") => "TimeSpan", - ("string", "time") => "TimeOnly", - ("string", "date") => "DateOnly", - ("string", "date-time") => "DateTimeOffset", - ("string", "uuid") => "Guid", - ("string", _) => "string", // covers commonmark and html - ("number", "double" or "float" or "decimal") => format.ToLowerInvariant(), - ("number" or "integer", "int8") => "sbyte", - ("number" or "integer", "uint8") => "byte", - ("number" or "integer", "int64") => "int64", - ("number", "int16") => "integer", - ("number", "int32") => "integer", - ("number", _) => "double", - ("integer", _) => "integer", - ("boolean", _) => "boolean", - (_, "byte") => "base64", - (_, "binary") => "binary", - (_, _) => string.Empty, - }; - if (!string.IsNullOrEmpty(primitiveTypeName)) - { - typeName = primitiveTypeName; - isExternal = true; - } - } - if (string.IsNullOrEmpty(typeName)) - return null; - return new CodeType - { - Name = typeName, - IsExternal = isExternal, + var typeName = typeNames.Find(static x => x is not null && !typeNamesToSkip.Contains(x.Value)); + + var format = typeSchema?.Format ?? typeSchema?.Items?.Format; + return (typeName, format?.ToLowerInvariant()) switch + { + (_, "byte") => new CodeType { Name = "base64", IsExternal = true }, + (_, "binary") => new CodeType { Name = "binary", IsExternal = true }, + (JsonSchemaType.String, "base64url") => new CodeType { Name = "base64url", IsExternal = true }, + (JsonSchemaType.String, "duration") => new CodeType { Name = "TimeSpan", IsExternal = true }, + (JsonSchemaType.String, "time") => new CodeType { Name = "TimeOnly", IsExternal = true }, + (JsonSchemaType.String, "date") => new CodeType { Name = "DateOnly", IsExternal = true }, + (JsonSchemaType.String, "date-time") => new CodeType { Name = "DateTimeOffset", IsExternal = true }, + (JsonSchemaType.String, "uuid") => new CodeType { Name = "Guid", IsExternal = true }, + (JsonSchemaType.String, _) => new CodeType { Name = "string", IsExternal = true }, // covers commonmark and html + (JsonSchemaType.Number, "double" or "float" or "decimal") => new CodeType { Name = format.ToLowerInvariant(), IsExternal = true }, + (JsonSchemaType.Number or JsonSchemaType.Integer, "int8") => new CodeType { Name = "sbyte", IsExternal = true }, + (JsonSchemaType.Number or JsonSchemaType.Integer, "uint8") => new CodeType { Name = "byte", IsExternal = true }, + (JsonSchemaType.Number or JsonSchemaType.Integer, "int64") => new CodeType { Name = "int64", IsExternal = true }, + (JsonSchemaType.Number, "int16") => new CodeType { Name = "integer", IsExternal = true }, + (JsonSchemaType.Number, "int32") => new CodeType { Name = "integer", IsExternal = true }, + (JsonSchemaType.Number, _) => new CodeType { Name = "double", IsExternal = true }, + (JsonSchemaType.Integer, _) => new CodeType { Name = "integer", IsExternal = true }, + (JsonSchemaType.Boolean, _) => new CodeType { Name = "boolean", IsExternal = true }, + //TODO handle the case where we have multiple entries + (_, _) when !string.IsNullOrEmpty(childType) => new CodeType { Name = childType, IsExternal = false, }, + (_, _) => null, }; } private const string RequestBodyPlainTextContentType = "text/plain"; @@ -1185,6 +1175,7 @@ openApiExtension is OpenApiPrimaryErrorMessageExtension primaryErrorMessageExten .Concat([CodeMethod.ErrorMappingClientRange, CodeMethod.ErrorMappingServerRange]), StringComparer.OrdinalIgnoreCase); private void AddErrorMappingsForExecutorMethod(OpenApiUrlTreeNode currentNode, OpenApiOperation operation, CodeMethod executorMethod) { + if (operation.Responses is null) return; foreach (var response in operation.Responses.Where(x => errorStatusCodes.Contains(x.Key))) { if (response.Value.GetResponseSchema(config.StructuredMimeTypes) is { } schema) @@ -1281,11 +1272,11 @@ private void AddErrorMappingToExecutorMethod(OpenApiUrlTreeNode currentNode, Ope private static CodeType GetExecutorMethodDefaultReturnType(OpenApiOperation operation) { string returnType; - if (operation.Responses.Any(static x => x.Value.Content.ContainsKey(RequestBodyOctetStreamContentType) && redirectStatusCodes.Contains(x.Key))) + if (operation.Responses?.Any(static x => x.Value.Content.ContainsKey(RequestBodyOctetStreamContentType) && redirectStatusCodes.Contains(x.Key)) is true) returnType = "binary"; - else if (operation.Responses.Any(static x => noContentStatusCodes.Contains(x.Key))) + else if (operation.Responses?.Any(static x => noContentStatusCodes.Contains(x.Key)) is true) returnType = VoidType; - else if (operation.Responses.Any(static x => x.Value.Content.ContainsKey(RequestBodyPlainTextContentType))) + else if (operation.Responses?.Any(static x => x.Value.Content.ContainsKey(RequestBodyPlainTextContentType)) is true) returnType = "string"; else returnType = "binary"; @@ -1329,7 +1320,7 @@ private void CreateOperationMethods(OpenApiUrlTreeNode currentNode, OperationTyp Deprecation = deprecationInformation, }; - if (operation.Extensions.TryGetValue(OpenApiPagingExtension.Name, out var extension) && extension is OpenApiPagingExtension pagingExtension) + if (operation.Extensions is not null && operation.Extensions.TryGetValue(OpenApiPagingExtension.Name, out var extension) && extension is OpenApiPagingExtension pagingExtension) { executorMethod.PagingInformation = new PagingInformation { @@ -1388,19 +1379,20 @@ private void CreateOperationMethods(OpenApiUrlTreeNode currentNode, OperationTyp && currentNode.HasRequiredQueryParametersAcrossOperations())// no need to generate extra strings/templates as optional parameters will have no effect on resolved url. generatorMethod.UrlTemplateOverride = operationUrlTemplate; - var mediaTypes = schema switch + var mediaTypes = (schema, operation.Responses is null) switch { - null => operation.Responses + (_, true) => [], + (null, _) => operation.Responses! .Where(static x => !errorStatusCodes.Contains(x.Key)) .SelectMany(static x => x.Value.Content) .Select(static x => x.Key) //get the successful non structured media types first, with a default 1 priority .Union(config.StructuredMimeTypes.GetAcceptedTypes( - operation.Responses + operation.Responses! .Where(static x => errorStatusCodes.Contains(x.Key)) // get any structured error ones, with the priority from the configuration .SelectMany(static x => x.Value.Content) // we can safely ignore unstructured ones as they won't be used in error mappings anyway and the body won't be read .Select(static x => x.Key))) .Distinct(StringComparer.OrdinalIgnoreCase), - _ => config.StructuredMimeTypes.GetAcceptedTypes(operation.Responses.Values.SelectMany(static x => x.Content).Where(x => schemaReferenceComparer.Equals(schema, x.Value.Schema)).Select(static x => x.Key)), + (_, false) => config.StructuredMimeTypes.GetAcceptedTypes(operation.Responses!.Values.SelectMany(static x => x.Content).Where(x => schemaReferenceComparer.Equals(schema, x.Value.Schema)).Select(static x => x.Key)), }; generatorMethod.AddAcceptedResponsesTypes(mediaTypes); if (config.Language == GenerationLanguage.CLI) @@ -1447,8 +1439,9 @@ private static void SetPathAndQueryParameters(CodeMethod target, OpenApiUrlTreeN .Select(GetCodeParameterFromApiParameter) .Union(operation .Parameters - .Where(ParametersFilter) - .Select(GetCodeParameterFromApiParameter)) + ?.Where(ParametersFilter) + .Select(GetCodeParameterFromApiParameter) ?? + []) .ToArray(); target.AddPathQueryOrHeaderParameter(pathAndQueryParameters); } @@ -1510,14 +1503,15 @@ private static bool IsSupportedMultipartDefault(OpenApiSchema openApiSchema, private void AddRequestBuilderMethodParameters(OpenApiUrlTreeNode currentNode, OperationType operationType, OpenApiOperation operation, CodeClass requestConfigClass, CodeMethod method) { - if (operation.GetRequestSchema(config.StructuredMimeTypes) is OpenApiSchema requestBodySchema) + if (operation.RequestBody is not null && + operation.GetRequestSchema(config.StructuredMimeTypes) is OpenApiSchema requestBodySchema) { CodeTypeBase requestBodyType; if (operation.RequestBody.Content.IsMultipartFormDataSchema(config.StructuredMimeTypes) && operation.RequestBody.Content.IsMultipartTopMimeType(config.StructuredMimeTypes)) { var mediaType = operation.RequestBody.Content.First(x => x.Value.Schema == requestBodySchema).Value; - if (mediaType.Encoding.Any()) + if (mediaType.Encoding is not null && mediaType.Encoding.Any()) { requestBodyType = new CodeType { Name = "MultipartBody", IsExternal = true, }; foreach (var encodingEntry in mediaType.Encoding @@ -1833,7 +1827,7 @@ private CodeTypeBase CreateModelDeclarations(OpenApiUrlTreeNode currentNode, Ope return CreateComposedModelDeclaration(currentNode, schema, operation, suffix, codeNamespace, isRequestBody, typeNameForInlineSchema); } - if (schema.IsObjectType() || schema.HasAnyProperty() || schema.IsEnum() || !string.IsNullOrEmpty(schema.AdditionalProperties?.Type)) + if (schema.IsObjectType() || schema.HasAnyProperty() || schema.IsEnum() || schema.AdditionalProperties?.Type is not null) { // no inheritance or union type, often empty definitions with only additional properties are used as property bags. return CreateModelDeclarationAndType(currentNode, schema, operation, codeNamespace, suffix, response: responseValue, typeNameForInlineSchema: typeNameForInlineSchema, isRequestBody); @@ -1846,8 +1840,8 @@ private CodeTypeBase CreateModelDeclarations(OpenApiUrlTreeNode currentNode, Ope return CreateCollectionModelDeclaration(currentNode, schema, operation, codeNamespace, typeNameForInlineSchema, isRequestBody); } - if (!string.IsNullOrEmpty(schema.Type) || !string.IsNullOrEmpty(schema.Format)) - return GetPrimitiveType(schema, string.Empty) ?? new CodeType { Name = UntypedNodeName, IsExternal = true }; + if (schema.Type is not null || !string.IsNullOrEmpty(schema.Format)) + return GetPrimitiveType(schema) ?? new CodeType { Name = UntypedNodeName, IsExternal = true }; if ((schema.AnyOf.Any() || schema.OneOf.Any() || schema.AllOf.Any()) && (schema.AnyOf.FirstOrDefault(static x => x.IsSemanticallyMeaningful(true)) ?? schema.OneOf.FirstOrDefault(static x => x.IsSemanticallyMeaningful(true)) ?? schema.AllOf.FirstOrDefault(static x => x.IsSemanticallyMeaningful(true))) is { } childSchema) // we have an empty node because of some local override for schema properties and need to unwrap it. return CreateModelDeclarations(currentNode, childSchema, operation, parentElement, suffixForInlineSchema, response, typeNameForInlineSchema, isRequestBody); @@ -1855,7 +1849,7 @@ private CodeTypeBase CreateModelDeclarations(OpenApiUrlTreeNode currentNode, Ope } private CodeTypeBase CreateCollectionModelDeclaration(OpenApiUrlTreeNode currentNode, OpenApiSchema schema, OpenApiOperation? operation, CodeNamespace codeNamespace, string typeNameForInlineSchema, bool isRequestBody) { - CodeTypeBase? type = GetPrimitiveType(schema.Items, string.Empty); + CodeTypeBase? type = GetPrimitiveType(schema.Items); var isEnumOrComposedCollectionType = schema.Items.IsEnum() //the collection could be an enum type so override with strong type instead of string type. || schema.Items.IsComposedEnum() && string.IsNullOrEmpty(schema.Items.Format);//the collection could be a composed type with an enum type so override with strong type instead of string type. if ((string.IsNullOrEmpty(type?.Name) @@ -1950,9 +1944,10 @@ private static void SetEnumOptions(OpenApiSchema schema, CodeEnum target) OpenApiEnumValuesDescriptionExtension? extensionInformation = null; if (schema.Extensions.TryGetValue(OpenApiEnumValuesDescriptionExtension.Name, out var rawExtension) && rawExtension is OpenApiEnumValuesDescriptionExtension localExtInfo) extensionInformation = localExtInfo; - target.AddOption(schema.Enum.OfType() - .Where(static x => !x.Value.Equals("null", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(x.Value)) - .Select(static x => x.Value) + target.AddOption(schema.Enum.OfType() + .Where(static x => x.GetValueKind() is JsonValueKind.String or JsonValueKind.Number) + .Select(static x => x.GetValueKind() is JsonValueKind.String ? x.GetValue() : x.GetValue().ToString(CultureInfo.InvariantCulture)) + .Where(static x => !string.IsNullOrEmpty(x)) .Distinct(StringComparer.OrdinalIgnoreCase) .Select((x) => { @@ -2225,13 +2220,16 @@ internal static void AddDiscriminatorMethod(CodeClass newClass, string discrimin private CodeType? GetCodeTypeForMapping(OpenApiUrlTreeNode currentNode, string referenceId, CodeNamespace currentNamespace, CodeClass? baseClass, OpenApiOperation? currentOperation) { var componentKey = referenceId?.Replace("#/components/schemas/", string.Empty, StringComparison.OrdinalIgnoreCase); - if (openApiDocument == null || !openApiDocument.Components.Schemas.TryGetValue(componentKey, out var discriminatorSchema)) + if (openApiDocument == null || string.IsNullOrEmpty(componentKey) || openApiDocument.Components?.Schemas is null || !openApiDocument.Components.Schemas.TryGetValue(componentKey, out var discriminatorSchema)) { logger.LogWarning("Discriminator {ComponentKey} not found in the OpenAPI document.", componentKey); return null; } + // the new version of OAI.net does not mutate the source schema anymore when resolving references which is a positive thing but is challenging for naming. + var schemaClone = new OpenApiSchema(discriminatorSchema); + schemaClone.Reference ??= new OpenApiReference { Id = componentKey, Type = ReferenceType.Schema }; // Call CreateModelDeclarations with isViaDiscriminator=true. This is for a special case where we always generate a base class when types are referenced via a oneOf discriminator. - if (CreateModelDeclarations(currentNode, discriminatorSchema, currentOperation, GetShortestNamespace(currentNamespace, discriminatorSchema), string.Empty, null, string.Empty, false, true) is not CodeType result) + if (CreateModelDeclarations(currentNode, schemaClone, currentOperation, GetShortestNamespace(currentNamespace, schemaClone), string.Empty, null, string.Empty, false, true) is not CodeType result) { logger.LogWarning("Discriminator {ComponentKey} is not a valid model and points to a union type.", componentKey); return null; @@ -2390,7 +2388,7 @@ internal static void AddSerializationMembers(CodeClass model, bool includeAdditi } private CodeClass? CreateOperationParameterClass(OpenApiUrlTreeNode node, OperationType operationType, OpenApiOperation operation, CodeClass parentClass) { - var parameters = node.PathItems[Constants.DefaultOpenApiLabel].Parameters.Union(operation.Parameters).Where(static p => p.In == ParameterLocation.Query).ToArray(); + var parameters = node.PathItems[Constants.DefaultOpenApiLabel].Parameters.Union(operation.Parameters ?? Enumerable.Empty()).Where(static p => p.In == ParameterLocation.Query).ToArray(); if (parameters.Length != 0) { var parameterClass = parentClass.AddInnerClass(new CodeClass @@ -2500,7 +2498,7 @@ private static CodeType GetQueryParameterType(OpenApiSchema schema) var paramType = GetPrimitiveType(schema) ?? new() { IsExternal = true, - Name = schema.Items?.Type ?? schema.Type, + Name = schema.Items is not null && schema.Items.Type.ToIdentifier() is string name ? name : "null", }; paramType.CollectionKind = schema.IsArray() ? CodeTypeBase.CodeTypeCollectionKind.Array : default; diff --git a/src/Kiota.Builder/LanguageInformation.cs b/src/Kiota.Builder/LanguageInformation.cs index d58dfa3b6a..2966c90f81 100644 --- a/src/Kiota.Builder/LanguageInformation.cs +++ b/src/Kiota.Builder/LanguageInformation.cs @@ -1,9 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json; +using System.Text.Json.Nodes; using System.Text.Json.Serialization; using Kiota.Builder.Extensions; -using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -30,8 +31,9 @@ public SupportExperience SupportExperience #pragma warning disable CA2227 public HashSet StructuredMimeTypes { get; set; } = new(StringComparer.OrdinalIgnoreCase); #pragma warning restore CA2227 - public void SerializeAsV2(IOpenApiWriter writer) => SerializeAsV3(writer); - public void SerializeAsV3(IOpenApiWriter writer) + public void SerializeAsV2(IOpenApiWriter writer) => SerializeAsV31(writer); + public void SerializeAsV3(IOpenApiWriter writer) => SerializeAsV31(writer); + public void SerializeAsV31(IOpenApiWriter writer) { ArgumentNullException.ThrowIfNull(writer); writer.WriteStartObject(); @@ -44,38 +46,41 @@ public void SerializeAsV3(IOpenApiWriter writer) writer.WriteOptionalCollection(nameof(StructuredMimeTypes).ToFirstCharacterLowerCase(), StructuredMimeTypes, static (w, x) => w.WriteValue(x)); writer.WriteEndObject(); } - public static LanguageInformation Parse(IOpenApiAny source) + public static LanguageInformation Parse(JsonNode source) { - if (source is not OpenApiObject rawObject) throw new ArgumentOutOfRangeException(nameof(source)); + ArgumentNullException.ThrowIfNull(source); + if (source.GetValueKind() is not JsonValueKind.Object || + source.AsObject() is not JsonObject rawObject) throw new ArgumentOutOfRangeException(nameof(source)); var extension = new LanguageInformation(); - if (rawObject.TryGetValue(nameof(Dependencies).ToFirstCharacterLowerCase(), out var dependencies) && dependencies is OpenApiArray arrayValue) + if (rawObject.TryGetPropertyValue(nameof(Dependencies).ToFirstCharacterLowerCase(), out var dependencies) && dependencies is JsonArray arrayValue) { foreach (var entry in arrayValue) - extension.Dependencies.Add(LanguageDependency.Parse(entry)); + if (entry is not null) + extension.Dependencies.Add(LanguageDependency.Parse(entry)); } - if (rawObject.TryGetValue(nameof(DependencyInstallCommand).ToFirstCharacterLowerCase(), out var installCommand) && installCommand is OpenApiString stringValue) + if (rawObject.TryGetPropertyValue(nameof(DependencyInstallCommand).ToFirstCharacterLowerCase(), out var installCommand) && installCommand is JsonValue stringValue) { - extension.DependencyInstallCommand = stringValue.Value; + extension.DependencyInstallCommand = stringValue.GetValue(); } // not parsing the maturity level on purpose, we don't want APIs to be able to change that - if (rawObject.TryGetValue(nameof(ClientClassName).ToFirstCharacterLowerCase(), out var clientClassName) && clientClassName is OpenApiString clientClassNameValue) + if (rawObject.TryGetPropertyValue(nameof(ClientClassName).ToFirstCharacterLowerCase(), out var clientClassName) && clientClassName is JsonValue clientClassNameValue) { - extension.ClientClassName = clientClassNameValue.Value; + extension.ClientClassName = clientClassNameValue.GetValue(); } - if (rawObject.TryGetValue(nameof(ClientNamespaceName).ToFirstCharacterLowerCase(), out var clientNamespaceName) && clientNamespaceName is OpenApiString clientNamespaceNameValue) + if (rawObject.TryGetPropertyValue(nameof(ClientNamespaceName).ToFirstCharacterLowerCase(), out var clientNamespaceName) && clientNamespaceName is JsonValue clientNamespaceNameValue) { - extension.ClientNamespaceName = clientNamespaceNameValue.Value; + extension.ClientNamespaceName = clientNamespaceNameValue.GetValue(); } - if (rawObject.TryGetValue(nameof(StructuredMimeTypes).ToFirstCharacterLowerCase(), out var structuredMimeTypes) && structuredMimeTypes is OpenApiArray structuredMimeTypesValue) + if (rawObject.TryGetPropertyValue(nameof(StructuredMimeTypes).ToFirstCharacterLowerCase(), out var structuredMimeTypes) && structuredMimeTypes is JsonArray structuredMimeTypesValue) { - foreach (var entry in structuredMimeTypesValue.OfType()) - extension.StructuredMimeTypes.Add(entry.Value); + foreach (var entry in structuredMimeTypesValue.OfType()) + extension.StructuredMimeTypes.Add(entry.GetValue()); } - if (rawObject.TryGetValue(nameof(MaturityLevel).ToFirstCharacterLowerCase(), out var maturityLevel) && maturityLevel is OpenApiString maturityLevelValue && Enum.TryParse(maturityLevelValue.Value, true, out var parsedMaturityLevelValue)) + if (rawObject.TryGetPropertyValue(nameof(MaturityLevel).ToFirstCharacterLowerCase(), out var maturityLevel) && maturityLevel is JsonValue maturityLevelValue && maturityLevelValue.GetValueKind() is JsonValueKind.String && Enum.TryParse(maturityLevelValue.GetValue(), true, out var parsedMaturityLevelValue)) { extension.MaturityLevel = parsedMaturityLevelValue; } - if (rawObject.TryGetValue(nameof(SupportExperience).ToFirstCharacterLowerCase(), out var supportExperience) && supportExperience is OpenApiString supportExperienceValue && Enum.TryParse(supportExperienceValue.Value, true, out var parsedSupportExperienceValue)) + if (rawObject.TryGetPropertyValue(nameof(SupportExperience).ToFirstCharacterLowerCase(), out var supportExperience) && supportExperience is JsonValue supportExperienceValue && supportExperienceValue.GetValueKind() is JsonValueKind.String && Enum.TryParse(supportExperienceValue.GetValue(), true, out var parsedSupportExperienceValue)) { extension.SupportExperience = parsedSupportExperienceValue; } @@ -92,8 +97,9 @@ public DependencyType? DependencyType get; set; } private const string TypePropertyName = "type"; - public void SerializeAsV2(IOpenApiWriter writer) => SerializeAsV3(writer); - public void SerializeAsV3(IOpenApiWriter writer) + public void SerializeAsV2(IOpenApiWriter writer) => SerializeAsV31(writer); + public void SerializeAsV3(IOpenApiWriter writer) => SerializeAsV31(writer); + public void SerializeAsV31(IOpenApiWriter writer) { ArgumentNullException.ThrowIfNull(writer); writer.WriteStartObject(); @@ -105,19 +111,21 @@ public void SerializeAsV3(IOpenApiWriter writer) } writer.WriteEndObject(); } - public static LanguageDependency Parse(IOpenApiAny source) + public static LanguageDependency Parse(JsonNode source) { - if (source is not OpenApiObject rawObject) throw new ArgumentOutOfRangeException(nameof(source)); + ArgumentNullException.ThrowIfNull(source); + if (source.GetValueKind() is not JsonValueKind.Object || + source.AsObject() is not JsonObject rawObject) throw new ArgumentOutOfRangeException(nameof(source)); var extension = new LanguageDependency(); - if (rawObject.TryGetValue(nameof(Name).ToFirstCharacterLowerCase(), out var name) && name is OpenApiString stringValue) + if (rawObject.TryGetPropertyValue(nameof(Name).ToFirstCharacterLowerCase(), out var nameNode) && nameNode is JsonValue nameJsonValue && nameJsonValue.TryGetValue(out var nameValue)) { - extension.Name = stringValue.Value; + extension.Name = nameValue; } - if (rawObject.TryGetValue(nameof(Version).ToFirstCharacterLowerCase(), out var version) && version is OpenApiString versionValue) + if (rawObject.TryGetPropertyValue(nameof(Version).ToFirstCharacterLowerCase(), out var versionNode) && versionNode is JsonValue versionJsonValue && versionJsonValue.TryGetValue(out var versionValue)) { - extension.Version = versionValue.Value; + extension.Version = versionValue; } - if (rawObject.TryGetValue(TypePropertyName, out var typeValue) && typeValue is OpenApiString typeStringValue && Enum.TryParse(typeStringValue.Value, true, out var parsedTypeValue)) + if (rawObject.TryGetPropertyValue(TypePropertyName, out var typeNode) && typeNode is JsonValue typeJsonValue && typeJsonValue.TryGetValue(out var typeValue) && Enum.TryParse(typeValue, true, out var parsedTypeValue)) { extension.DependencyType = parsedTypeValue; } diff --git a/src/Kiota.Builder/OpenApiDocumentDownloadService.cs b/src/Kiota.Builder/OpenApiDocumentDownloadService.cs index ae586c86a3..1739f502b5 100644 --- a/src/Kiota.Builder/OpenApiDocumentDownloadService.cs +++ b/src/Kiota.Builder/OpenApiDocumentDownloadService.cs @@ -16,6 +16,7 @@ using Kiota.Builder.WorkspaceManagement; using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Readers; using Microsoft.OpenApi.Validations; @@ -30,6 +31,8 @@ public OpenApiDocumentDownloadService(HttpClient httpClient, ILogger logger) ArgumentNullException.ThrowIfNull(logger); HttpClient = httpClient; Logger = logger; + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader()); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yml, new OpenApiYamlReader()); } private static readonly AsyncKeyedLocker localFilesLock = new(o => { @@ -135,25 +138,24 @@ ex is SecurityException || { // couldn't parse the URL, it's probably a local file } - var reader = new OpenApiStreamReader(settings); - var readResult = await reader.ReadAsync(input, cancellationToken).ConfigureAwait(false); + var readResult = await OpenApiDocument.LoadAsync(input, settings: settings, cancellationToken: cancellationToken).ConfigureAwait(false); stopwatch.Stop(); if (generating) - foreach (var warning in readResult.OpenApiDiagnostic.Warnings) + foreach (var warning in readResult.Diagnostic.Warnings) Logger.LogWarning("OpenAPI warning: {Pointer} - {Warning}", warning.Pointer, warning.Message); - if (readResult.OpenApiDiagnostic.Errors.Any()) + if (readResult.Diagnostic.Errors.Any()) { - Logger.LogTrace("{Timestamp}ms: Parsed OpenAPI with errors. {Count} paths found.", stopwatch.ElapsedMilliseconds, readResult.OpenApiDocument?.Paths?.Count ?? 0); - foreach (var parsingError in readResult.OpenApiDiagnostic.Errors) + Logger.LogTrace("{Timestamp}ms: Parsed OpenAPI with errors. {Count} paths found.", stopwatch.ElapsedMilliseconds, readResult.Document?.Paths?.Count ?? 0); + foreach (var parsingError in readResult.Diagnostic.Errors) { Logger.LogError("OpenAPI error: {Pointer} - {Message}", parsingError.Pointer, parsingError.Message); } } else { - Logger.LogTrace("{Timestamp}ms: Parsed OpenAPI successfully. {Count} paths found.", stopwatch.ElapsedMilliseconds, readResult.OpenApiDocument?.Paths?.Count ?? 0); + Logger.LogTrace("{Timestamp}ms: Parsed OpenAPI successfully. {Count} paths found.", stopwatch.ElapsedMilliseconds, readResult.Document?.Paths?.Count ?? 0); } - return readResult.OpenApiDocument; + return readResult.Document; } } diff --git a/src/Kiota.Builder/OpenApiExtensions/OpenApiAiReasoningInstructionsExtension.cs b/src/Kiota.Builder/OpenApiExtensions/OpenApiAiReasoningInstructionsExtension.cs index f690e1df81..8cfd72a30e 100644 --- a/src/Kiota.Builder/OpenApiExtensions/OpenApiAiReasoningInstructionsExtension.cs +++ b/src/Kiota.Builder/OpenApiExtensions/OpenApiAiReasoningInstructionsExtension.cs @@ -1,8 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.OpenApi; -using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -28,11 +29,11 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion) writer.WriteEndArray(); } } - public static OpenApiAiReasoningInstructionsExtension Parse(IOpenApiAny source) + public static OpenApiAiReasoningInstructionsExtension Parse(JsonNode source) { - if (source is not OpenApiArray rawArray) throw new ArgumentOutOfRangeException(nameof(source)); + if (source is not JsonArray rawArray) throw new ArgumentOutOfRangeException(nameof(source)); var result = new OpenApiAiReasoningInstructionsExtension(); - result.ReasoningInstructions.AddRange(rawArray.OfType().Select(x => x.Value)); + result.ReasoningInstructions.AddRange(rawArray.OfType().Where(static x => x.GetValueKind() is JsonValueKind.String).Select(static x => x.GetValue())); return result; } } diff --git a/src/Kiota.Builder/OpenApiExtensions/OpenApiAiRespondingInstructionsExtension.cs b/src/Kiota.Builder/OpenApiExtensions/OpenApiAiRespondingInstructionsExtension.cs index b8137ec225..440f90f03b 100644 --- a/src/Kiota.Builder/OpenApiExtensions/OpenApiAiRespondingInstructionsExtension.cs +++ b/src/Kiota.Builder/OpenApiExtensions/OpenApiAiRespondingInstructionsExtension.cs @@ -1,8 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.OpenApi; -using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -28,11 +29,11 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion) writer.WriteEndArray(); } } - public static OpenApiAiRespondingInstructionsExtension Parse(IOpenApiAny source) + public static OpenApiAiRespondingInstructionsExtension Parse(JsonNode source) { - if (source is not OpenApiArray rawArray) throw new ArgumentOutOfRangeException(nameof(source)); + if (source is not JsonArray rawArray) throw new ArgumentOutOfRangeException(nameof(source)); var result = new OpenApiAiRespondingInstructionsExtension(); - result.RespondingInstructions.AddRange(rawArray.OfType().Select(x => x.Value)); + result.RespondingInstructions.AddRange(rawArray.OfType().Where(static x => x.GetValueKind() is JsonValueKind.String).Select(static x => x.GetValue())); return result; } } diff --git a/src/Kiota.Builder/OpenApiExtensions/OpenApiDescriptionForModelExtension.cs b/src/Kiota.Builder/OpenApiExtensions/OpenApiDescriptionForModelExtension.cs index ba198df7c9..0a174f9fa3 100644 --- a/src/Kiota.Builder/OpenApiExtensions/OpenApiDescriptionForModelExtension.cs +++ b/src/Kiota.Builder/OpenApiExtensions/OpenApiDescriptionForModelExtension.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Any; +using System.Text.Json.Nodes; namespace Kiota.Builder.OpenApiExtensions; @@ -10,7 +10,7 @@ public string? Description get; set; } protected override string? ValueSelector => Description; - public static OpenApiDescriptionForModelExtension Parse(IOpenApiAny source) + public static OpenApiDescriptionForModelExtension Parse(JsonNode source) { return new OpenApiDescriptionForModelExtension { diff --git a/src/Kiota.Builder/OpenApiExtensions/OpenApiKiotaExtension.cs b/src/Kiota.Builder/OpenApiExtensions/OpenApiKiotaExtension.cs index 80a9149f2f..6c7d9398d8 100644 --- a/src/Kiota.Builder/OpenApiExtensions/OpenApiKiotaExtension.cs +++ b/src/Kiota.Builder/OpenApiExtensions/OpenApiKiotaExtension.cs @@ -1,9 +1,9 @@ using System; using System.Linq; +using System.Text.Json.Nodes; using Kiota.Builder.Configuration; using Kiota.Builder.Extensions; using Microsoft.OpenApi; -using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -30,11 +30,11 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion) writer.WriteEndObject(); } } - public static OpenApiKiotaExtension Parse(IOpenApiAny source) + public static OpenApiKiotaExtension Parse(JsonNode source) { - if (source is not OpenApiObject rawObject) throw new ArgumentOutOfRangeException(nameof(source)); + if (source is not JsonObject jsonNode) throw new ArgumentOutOfRangeException(nameof(source)); var extension = new OpenApiKiotaExtension(); - if (rawObject.TryGetValue(nameof(LanguagesInformation).ToFirstCharacterLowerCase(), out var languagesInfo) && languagesInfo is OpenApiObject objectValue) + if (jsonNode.TryGetPropertyValue(nameof(LanguagesInformation).ToFirstCharacterLowerCase(), out var languagesInfo) && languagesInfo is JsonObject objectValue) { extension.LanguagesInformation = LanguagesInformation.Parse(objectValue); } diff --git a/src/Kiota.Builder/OpenApiExtensions/OpenApiLegalInfoUrlExtension.cs b/src/Kiota.Builder/OpenApiExtensions/OpenApiLegalInfoUrlExtension.cs index 3f042fc70c..10a52bce1a 100644 --- a/src/Kiota.Builder/OpenApiExtensions/OpenApiLegalInfoUrlExtension.cs +++ b/src/Kiota.Builder/OpenApiExtensions/OpenApiLegalInfoUrlExtension.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Any; +using System.Text.Json.Nodes; namespace Kiota.Builder.OpenApiExtensions; @@ -10,7 +10,7 @@ public string? Legal get; set; } protected override string? ValueSelector => Legal; - public static OpenApiLegalInfoUrlExtension Parse(IOpenApiAny source) + public static OpenApiLegalInfoUrlExtension Parse(JsonNode source) { return new OpenApiLegalInfoUrlExtension { diff --git a/src/Kiota.Builder/OpenApiExtensions/OpenApiLogoExtension.cs b/src/Kiota.Builder/OpenApiExtensions/OpenApiLogoExtension.cs index edd5a2daf5..6ddab21631 100644 --- a/src/Kiota.Builder/OpenApiExtensions/OpenApiLogoExtension.cs +++ b/src/Kiota.Builder/OpenApiExtensions/OpenApiLogoExtension.cs @@ -1,7 +1,8 @@ using System; +using System.Text.Json; +using System.Text.Json.Nodes; using Kiota.Builder.Extensions; using Microsoft.OpenApi; -using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -16,13 +17,13 @@ public string? Url { get; set; } - public static OpenApiLogoExtension Parse(IOpenApiAny source) + public static OpenApiLogoExtension Parse(JsonNode source) { - if (source is not OpenApiObject rawObject) throw new ArgumentOutOfRangeException(nameof(source)); + if (source is not JsonObject rawObject) throw new ArgumentOutOfRangeException(nameof(source)); var extension = new OpenApiLogoExtension(); - if (rawObject.TryGetValue(nameof(Url).ToFirstCharacterLowerCase(), out var url) && url is OpenApiString urlValue) + if (rawObject.TryGetPropertyValue(nameof(Url).ToFirstCharacterLowerCase(), out var url) && url is JsonValue urlValue && urlValue.GetValueKind() is JsonValueKind.String && urlValue.TryGetValue(out var urlStrValue)) { - extension.Url = urlValue.Value; + extension.Url = urlStrValue; } return extension; } diff --git a/src/Kiota.Builder/OpenApiExtensions/OpenApiPrivacyPolicyUrlExtension.cs b/src/Kiota.Builder/OpenApiExtensions/OpenApiPrivacyPolicyUrlExtension.cs index 4cbc47c72a..039b2f54fe 100644 --- a/src/Kiota.Builder/OpenApiExtensions/OpenApiPrivacyPolicyUrlExtension.cs +++ b/src/Kiota.Builder/OpenApiExtensions/OpenApiPrivacyPolicyUrlExtension.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Any; +using System.Text.Json.Nodes; namespace Kiota.Builder.OpenApiExtensions; @@ -10,7 +10,7 @@ public string? Privacy get; set; } protected override string? ValueSelector => Privacy; - public static OpenApiPrivacyPolicyUrlExtension Parse(IOpenApiAny source) + public static OpenApiPrivacyPolicyUrlExtension Parse(JsonNode source) { return new OpenApiPrivacyPolicyUrlExtension { diff --git a/src/Kiota.Builder/OpenApiExtensions/OpenApiSimpleStringExtension.cs b/src/Kiota.Builder/OpenApiExtensions/OpenApiSimpleStringExtension.cs index 9978939205..53ba859256 100644 --- a/src/Kiota.Builder/OpenApiExtensions/OpenApiSimpleStringExtension.cs +++ b/src/Kiota.Builder/OpenApiExtensions/OpenApiSimpleStringExtension.cs @@ -1,6 +1,7 @@ using System; +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.OpenApi; -using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -20,9 +21,10 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion) writer.WriteValue(ValueSelector); } } - public static string ParseString(IOpenApiAny source) + public static string ParseString(JsonNode source) { - if (source is not OpenApiString rawString) throw new ArgumentOutOfRangeException(nameof(source)); - return rawString.Value; + if (source is not JsonValue rawString || + rawString.GetValueKind() is not JsonValueKind.String) throw new ArgumentOutOfRangeException(nameof(source)); + return rawString.GetValue(); } } diff --git a/src/Kiota.Builder/Plugins/PluginsGenerationService.cs b/src/Kiota.Builder/Plugins/PluginsGenerationService.cs index 1406aa91c7..58a3458cbc 100644 --- a/src/Kiota.Builder/Plugins/PluginsGenerationService.cs +++ b/src/Kiota.Builder/Plugins/PluginsGenerationService.cs @@ -117,7 +117,7 @@ public override void Visit(OpenApiSchema schema) { if (schema.Discriminator?.Mapping is null) return; - var keysToRemove = schema.Discriminator.Mapping.Where(x => !_document.Components.Schemas.ContainsKey(x.Value.Split('/', StringSplitOptions.RemoveEmptyEntries)[^1])).Select(static x => x.Key).ToArray(); + var keysToRemove = schema.Discriminator.Mapping.Where(x => _document.Components?.Schemas is null || !_document.Components.Schemas.ContainsKey(x.Value.Split('/', StringSplitOptions.RemoveEmptyEntries)[^1])).Select(static x => x.Key).ToArray(); foreach (var key in keysToRemove) schema.Discriminator.Mapping.Remove(key); base.Visit(schema); @@ -165,7 +165,7 @@ public override void Visit(OpenApiSchema schema) } internal static void CopyRelevantInformation(OpenApiSchema source, OpenApiSchema target, bool includeProperties = true, bool includeReference = true, bool includeDiscriminator = true) { - if (!string.IsNullOrEmpty(source.Type)) + if (source.Type is not null && source.Type.HasValue) target.Type = source.Type; if (!string.IsNullOrEmpty(source.Format)) target.Format = source.Format; @@ -425,7 +425,7 @@ private static (OpenApiRuntime[], Function[], ConversationStarter[]) GetRuntimes var auth = configAuth; try { - auth = configAuth ?? GetAuth(operation.Security ?? document.SecurityRequirements); + auth = configAuth ?? GetAuth(operation.Security ?? document.SecurityRequirements ?? []); } catch (UnsupportedSecuritySchemeException e) { @@ -438,7 +438,7 @@ private static (OpenApiRuntime[], Function[], ConversationStarter[]) GetRuntimes // Configuration overrides document information Auth = auth, Spec = new OpenApiRuntimeSpec { Url = openApiDocumentPath }, - RunForFunctions = [operation.OperationId] + RunForFunctions = [operation.OperationId!] }); var summary = operation.Summary.CleanupXMLString(); @@ -446,7 +446,7 @@ private static (OpenApiRuntime[], Function[], ConversationStarter[]) GetRuntimes functions.Add(new Function { - Name = operation.OperationId, + Name = operation.OperationId!, Description = !string.IsNullOrEmpty(description) ? description : summary, States = GetStatesFromOperation(operation), @@ -526,7 +526,8 @@ SecuritySchemeType.Http when securityScheme.Scheme.Equals("bearer", StringCompar private static State? GetStateFromExtension(OpenApiOperation openApiOperation, string extensionName, Func> instructionsExtractor) { - if (openApiOperation.Extensions.TryGetValue(extensionName, out var rExtRaw) && + if (openApiOperation.Extensions is not null && + openApiOperation.Extensions.TryGetValue(extensionName, out var rExtRaw) && rExtRaw is T rExt && instructionsExtractor(rExt).Exists(static x => !string.IsNullOrEmpty(x))) { diff --git a/src/Kiota.Builder/Validation/InconsistentTypeFormatPair.cs b/src/Kiota.Builder/Validation/InconsistentTypeFormatPair.cs index 636bf96689..ecdd6edc2f 100644 --- a/src/Kiota.Builder/Validation/InconsistentTypeFormatPair.cs +++ b/src/Kiota.Builder/Validation/InconsistentTypeFormatPair.cs @@ -7,9 +7,9 @@ namespace Kiota.Builder.Validation; public class InconsistentTypeFormatPair : ValidationRule { - private static readonly Dictionary> validPairs = new(StringComparer.OrdinalIgnoreCase) + private static readonly Dictionary> validPairs = new() { - ["string"] = new(StringComparer.OrdinalIgnoreCase) { + [JsonSchemaType.String] = new(StringComparer.OrdinalIgnoreCase) { "commonmark", "html", "date", @@ -21,7 +21,7 @@ public class InconsistentTypeFormatPair : ValidationRule "binary", "byte", }, - ["integer"] = new(StringComparer.OrdinalIgnoreCase) { + [JsonSchemaType.Integer] = new(StringComparer.OrdinalIgnoreCase) { "int32", "int64", "int8", @@ -29,7 +29,7 @@ public class InconsistentTypeFormatPair : ValidationRule "int16", "uint16", }, - ["number"] = new(StringComparer.OrdinalIgnoreCase) { + [JsonSchemaType.Number] = new(StringComparer.OrdinalIgnoreCase) { "float", "double", "decimal", @@ -41,19 +41,17 @@ public class InconsistentTypeFormatPair : ValidationRule "uint16", }, }; - private static readonly HashSet escapedTypes = new(StringComparer.OrdinalIgnoreCase) { - "array", - "boolean", - "const", - "enum", - "null", - "object", - }; + private static readonly HashSet escapedTypes = [ + JsonSchemaType.Array, + JsonSchemaType.Boolean, + JsonSchemaType.Null, + JsonSchemaType.Object, + ]; public InconsistentTypeFormatPair() : base(nameof(InconsistentTypeFormatPair), static (context, schema) => { - if (string.IsNullOrEmpty(schema?.Type) || string.IsNullOrEmpty(schema.Format) || KnownAndNotSupportedFormats.knownAndUnsupportedFormats.Contains(schema.Format) || escapedTypes.Contains(schema.Type)) + if (schema is null || !schema.Type.HasValue || string.IsNullOrEmpty(schema.Format) || KnownAndNotSupportedFormats.knownAndUnsupportedFormats.Contains(schema.Format) || escapedTypes.Contains(schema.Type.Value)) return; - if (!validPairs.TryGetValue(schema.Type, out var validFormats) || !validFormats.Contains(schema.Format)) + if (!validPairs.TryGetValue(schema.Type.Value, out var validFormats) || !validFormats.Contains(schema.Format)) context.CreateWarning(nameof(InconsistentTypeFormatPair), $"The format {schema.Format} is not supported by Kiota for the type {schema.Type} and the string type will be used."); }) { diff --git a/src/Kiota.Builder/Validation/MissingDiscriminator.cs b/src/Kiota.Builder/Validation/MissingDiscriminator.cs index c889f5cf5a..4fa5b52064 100644 --- a/src/Kiota.Builder/Validation/MissingDiscriminator.cs +++ b/src/Kiota.Builder/Validation/MissingDiscriminator.cs @@ -14,7 +14,7 @@ public MissingDiscriminator(GenerationConfiguration configuration) : base(nameof { var idx = new ConcurrentDictionary>(StringComparer.OrdinalIgnoreCase); document.InitializeInheritanceIndex(idx); - if (document.Components != null) + if (document.Components is { Schemas.Count: > 0 }) Parallel.ForEach(document.Components.Schemas, entry => { ValidateSchema(entry.Value, context, idx, entry.Key); diff --git a/src/Kiota.Builder/Validation/MultipleServerEntries.cs b/src/Kiota.Builder/Validation/MultipleServerEntries.cs index 05ff96e5c5..98b3dd2167 100644 --- a/src/Kiota.Builder/Validation/MultipleServerEntries.cs +++ b/src/Kiota.Builder/Validation/MultipleServerEntries.cs @@ -8,7 +8,7 @@ public class MultipleServerEntries : ValidationRule { public MultipleServerEntries() : base(nameof(MultipleServerEntries), static (context, document) => { - if (document.Servers.GroupBy(static x => x.Url, StringComparer.OrdinalIgnoreCase).Count() > 1) + if (document.Servers?.GroupBy(static x => x.Url, StringComparer.OrdinalIgnoreCase).Count() > 1) context.CreateWarning(nameof(MultipleServerEntries), "Multiple servers entries were found in the OpenAPI description. Only the first one will be used. The root URL can be set manually with the request adapter."); }) diff --git a/src/Kiota.Builder/Validation/NoContentWithBody.cs b/src/Kiota.Builder/Validation/NoContentWithBody.cs index 539c4430e7..29b1c5b960 100644 --- a/src/Kiota.Builder/Validation/NoContentWithBody.cs +++ b/src/Kiota.Builder/Validation/NoContentWithBody.cs @@ -8,7 +8,7 @@ public class NoContentWithBody : ValidationRule { public NoContentWithBody() : base(nameof(NoContentWithBody), static (context, operation) => { - if (operation.Responses.TryGetValue("204", out var response) && (response?.Content?.Any() ?? false)) + if (operation.Responses is not null && operation.Responses.TryGetValue("204", out var response) && (response?.Content?.Any() ?? false)) context.CreateWarning(nameof(NoContentWithBody), "A 204 response with a body media type was found. The response body will be ignored."); }) { diff --git a/src/Kiota.Builder/Validation/NoServerEntry.cs b/src/Kiota.Builder/Validation/NoServerEntry.cs index 17513ed4f7..895744b4b5 100644 --- a/src/Kiota.Builder/Validation/NoServerEntry.cs +++ b/src/Kiota.Builder/Validation/NoServerEntry.cs @@ -1,5 +1,4 @@ -using System.Linq; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Validations; namespace Kiota.Builder.Validation; @@ -8,7 +7,7 @@ public class NoServerEntry : ValidationRule { public NoServerEntry() : base(nameof(NoServerEntry), static (context, document) => { - if (!document.Servers.Any() || string.IsNullOrEmpty(document.Servers.First().Url?.TrimEnd('/'))) + if (document.Servers is not { Count: > 0 } || string.IsNullOrEmpty(document.Servers[0].Url?.TrimEnd('/'))) context.CreateWarning(nameof(NoServerEntry), "A servers entry (v3) or host + basePath + schemes properties (v2) was not present in the OpenAPI description. The root URL will need to be set manually with the request adapter."); }) diff --git a/src/Kiota.Builder/Validation/OpenApiSchemaComparer.cs b/src/Kiota.Builder/Validation/OpenApiSchemaComparer.cs index 5b145e9daa..1d7b2c1fcb 100644 --- a/src/Kiota.Builder/Validation/OpenApiSchemaComparer.cs +++ b/src/Kiota.Builder/Validation/OpenApiSchemaComparer.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Text.Json.Nodes; using Kiota.Builder.Extensions; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; @@ -11,16 +12,16 @@ namespace Kiota.Builder.Validation; internal class OpenApiSchemaComparer : IEqualityComparer { private readonly OpenApiDiscriminatorComparer discriminatorComparer; - private readonly OpenApiAnyComparer openApiAnyComparer; + private readonly JsonNodeComparer jsonNodeComparer; private readonly KeyValueComparer schemaMapComparer; public OpenApiSchemaComparer( OpenApiDiscriminatorComparer? discriminatorComparer = null, - OpenApiAnyComparer? openApiAnyComparer = null, + JsonNodeComparer? jsonNodeComparer = null, KeyValueComparer? schemaMapComparer = null) { this.discriminatorComparer = discriminatorComparer ?? new OpenApiDiscriminatorComparer(); - this.openApiAnyComparer = openApiAnyComparer ?? new OpenApiAnyComparer(); + this.jsonNodeComparer = jsonNodeComparer ?? new JsonNodeComparer(); this.schemaMapComparer = schemaMapComparer ?? new KeyValueComparer(StringComparer.Ordinal, this); } @@ -53,7 +54,7 @@ private void GetHashCodeInternal([DisallowNull] OpenApiSchema obj, HashSet +internal class JsonNodeComparer : IEqualityComparer { /// - public bool Equals(IOpenApiAny? x, IOpenApiAny? y) + public bool Equals(JsonNode? x, JsonNode? y) { if (x is null || y is null) return object.Equals(x, y); // TODO: Can we use the OpenAPI.NET implementation of Equals? - return x.AnyType == y.AnyType && string.Equals(x.ToString(), y.ToString(), StringComparison.OrdinalIgnoreCase); + return x.GetValueKind() == y.GetValueKind() && string.Equals(x.GetValue(), y.GetValue(), StringComparison.OrdinalIgnoreCase); } /// - public int GetHashCode([DisallowNull] IOpenApiAny obj) + public int GetHashCode([DisallowNull] JsonNode obj) { var hash = new HashCode(); if (obj == null) return hash.ToHashCode(); diff --git a/src/Kiota.Builder/Validation/UrlFormEncodedComplex.cs b/src/Kiota.Builder/Validation/UrlFormEncodedComplex.cs index 78a4b31572..917ba8a289 100644 --- a/src/Kiota.Builder/Validation/UrlFormEncodedComplex.cs +++ b/src/Kiota.Builder/Validation/UrlFormEncodedComplex.cs @@ -14,18 +14,18 @@ public class UrlFormEncodedComplex : ValidationRule public UrlFormEncodedComplex() : base(nameof(UrlFormEncodedComplex), static (context, operation) => { if (operation.GetRequestSchema(validContentTypes) is OpenApiSchema requestSchema) - ValidateSchema(requestSchema, context, operation.OperationId, "request body"); + ValidateSchema(requestSchema, context, "request body"); if (operation.GetResponseSchema(validContentTypes) is OpenApiSchema responseSchema) - ValidateSchema(responseSchema, context, operation.OperationId, "response body"); + ValidateSchema(responseSchema, context, "response body"); }) { } - private static void ValidateSchema(OpenApiSchema schema, IValidationContext context, string operationId, string schemaName) + private static void ValidateSchema(OpenApiSchema schema, IValidationContext context, string schemaName) { if (schema == null) return; if (!schema.IsObjectType()) - context.CreateWarning(nameof(UrlFormEncodedComplex), $"The operation {operationId} has a {schemaName} which is not an object type. This is not supported by Kiota and serialization will fail."); + context.CreateWarning(nameof(UrlFormEncodedComplex), $"The operation {context.PathString} has a {schemaName} which is not an object type. This is not supported by Kiota and serialization will fail."); if (schema.Properties.Any(static x => x.Value.IsObjectType())) - context.CreateWarning(nameof(UrlFormEncodedComplex), $"The operation {operationId} has a {schemaName} with a complex properties and the url form encoded content type. This is not supported by Kiota and serialization of complex properties will fail."); + context.CreateWarning(nameof(UrlFormEncodedComplex), $"The operation {context.PathString} has a {schemaName} with a complex properties and the url form encoded content type. This is not supported by Kiota and serialization of complex properties will fail."); } } diff --git a/src/Kiota.Builder/Validation/ValidationRuleSetExtensions.cs b/src/Kiota.Builder/Validation/ValidationRuleSetExtensions.cs index c54eb22904..523bbcfc3a 100644 --- a/src/Kiota.Builder/Validation/ValidationRuleSetExtensions.cs +++ b/src/Kiota.Builder/Validation/ValidationRuleSetExtensions.cs @@ -1,5 +1,6 @@ using System; using Kiota.Builder.Configuration; +using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Validations; namespace Kiota.Builder.Validation; @@ -13,18 +14,18 @@ public static void AddKiotaValidationRules(this ValidationRuleSet ruleSet, Gener configuration ??= new(); if (configuration.DisabledValidationRules.Contains(AllValidationRule)) return; - ruleSet.AddRuleIfEnabled(configuration, new NoServerEntry()); - ruleSet.AddRuleIfEnabled(configuration, new MultipleServerEntries()); - ruleSet.AddRuleIfEnabled(configuration, new GetWithBody()); - ruleSet.AddRuleIfEnabled(configuration, new KnownAndNotSupportedFormats()); - ruleSet.AddRuleIfEnabled(configuration, new InconsistentTypeFormatPair()); - ruleSet.AddRuleIfEnabled(configuration, new UrlFormEncodedComplex()); - ruleSet.AddRuleIfEnabled(configuration, new DivergentResponseSchema(configuration)); - ruleSet.AddRuleIfEnabled(configuration, new MissingDiscriminator(configuration)); + ruleSet.AddRuleIfEnabled(configuration, new NoServerEntry(), typeof(OpenApiDocument)); + ruleSet.AddRuleIfEnabled(configuration, new MultipleServerEntries(), typeof(OpenApiDocument)); + ruleSet.AddRuleIfEnabled(configuration, new GetWithBody(), typeof(OpenApiPathItem)); + ruleSet.AddRuleIfEnabled(configuration, new KnownAndNotSupportedFormats(), typeof(OpenApiSchema)); + ruleSet.AddRuleIfEnabled(configuration, new InconsistentTypeFormatPair(), typeof(OpenApiSchema)); + ruleSet.AddRuleIfEnabled(configuration, new UrlFormEncodedComplex(), typeof(OpenApiOperation)); + ruleSet.AddRuleIfEnabled(configuration, new DivergentResponseSchema(configuration), typeof(OpenApiOperation)); + ruleSet.AddRuleIfEnabled(configuration, new MissingDiscriminator(configuration), typeof(OpenApiDocument)); } - private static void AddRuleIfEnabled(this ValidationRuleSet ruleSet, GenerationConfiguration configuration, T instance) where T : ValidationRule + private static void AddRuleIfEnabled(this ValidationRuleSet ruleSet, GenerationConfiguration configuration, T instance, Type ruleType) where T : ValidationRule { - if (!configuration.DisabledValidationRules.Contains(instance.GetType().Name)) - ruleSet.Add(instance); + if (!configuration.DisabledValidationRules.Contains(typeof(T).Name)) + ruleSet.Add(ruleType, instance); } } diff --git a/src/kiota/kiota.csproj b/src/kiota/kiota.csproj index 8a313c04d5..2e2cb8fef4 100644 --- a/src/kiota/kiota.csproj +++ b/src/kiota/kiota.csproj @@ -46,8 +46,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tests/Kiota.Builder.Tests/ContentTypeMappingTests.cs b/tests/Kiota.Builder.Tests/ContentTypeMappingTests.cs index 07cd3bd7c4..1c1c020583 100644 --- a/tests/Kiota.Builder.Tests/ContentTypeMappingTests.cs +++ b/tests/Kiota.Builder.Tests/ContentTypeMappingTests.cs @@ -83,11 +83,11 @@ public void GeneratesTheRightReturnTypeBasedOnContentAndStatus(string contentTyp { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -177,11 +177,11 @@ public void GeneratesTheRightParameterTypeBasedOnContentAndStatus(string content { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -269,11 +269,11 @@ public void GeneratesTheRightAcceptHeaderBasedOnContentAndStatus(string contentM ["200"] = new OpenApiResponse { Content = contentMediaTypes.Split(',').Select(x => new {Key = x.Trim(), value = new OpenApiMediaType { Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -297,11 +297,11 @@ public void GeneratesTheRightAcceptHeaderBasedOnContentAndStatus(string contentM Schemas = new Dictionary { { "myobject", new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -360,11 +360,11 @@ public void GeneratesTheRightContentTypeHeaderBasedOnContentAndStatus(string con { Content = contentMediaTypes.Split(',').Select(x => new {Key = x.Trim(), value = new OpenApiMediaType { Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -387,11 +387,11 @@ public void GeneratesTheRightContentTypeHeaderBasedOnContentAndStatus(string con Schemas = new Dictionary { { "myobject", new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, diff --git a/tests/Kiota.Builder.Tests/Export/PublicAPIExportServiceTests.cs b/tests/Kiota.Builder.Tests/Export/PublicAPIExportServiceTests.cs index 51b4306f49..13465008e5 100644 --- a/tests/Kiota.Builder.Tests/Export/PublicAPIExportServiceTests.cs +++ b/tests/Kiota.Builder.Tests/Export/PublicAPIExportServiceTests.cs @@ -73,7 +73,7 @@ public void Defensive() Assert.Throws(() => new PublicApiExportService(null)); } - private static readonly Dictionary> Validators = new() + private static readonly Dictionary>> Validators = new() { { GenerationLanguage.CSharp, ValidateExportCSharp }, { GenerationLanguage.Go, ValidateExportGo }, @@ -122,7 +122,7 @@ public async Task GeneratesExportsAndFileHasExpectedAssertionsAsync(GenerationLa Assert.NotEqual(0, outputStream.Length); // output is not empty using var streamReader = new StreamReader(outputStream); - var contents = (await streamReader.ReadToEndAsync()).Split(Environment.NewLine); + var contents = new HashSet((await streamReader.ReadToEndAsync()).Split(Environment.NewLine), StringComparer.Ordinal); if (!Validators.TryGetValue(generationLanguage, out var validator)) { @@ -132,7 +132,7 @@ public async Task GeneratesExportsAndFileHasExpectedAssertionsAsync(GenerationLa validator.Invoke(contents); } - private static void ValidateExportCSharp(string[] exportContents) + private static void ValidateExportCSharp(HashSet exportContents) { Assert.NotEmpty(exportContents); Assert.Contains("ExportNamespace.Graph-->BaseRequestBuilder", exportContents); // captures class inheritance @@ -145,7 +145,7 @@ private static void ValidateExportCSharp(string[] exportContents) Assert.Contains("ExportNamespace.Models.Microsoft.Graph.user::|public|OtherNames:List", exportContents);// captures collection info in language specific format } - private static void ValidateExportJava(string[] exportContents) + private static void ValidateExportJava(HashSet exportContents) { Assert.NotEmpty(exportContents); Assert.Contains("exportnamespace.Graph-->BaseRequestBuilder", exportContents); // captures class inheritance @@ -160,7 +160,7 @@ private static void ValidateExportJava(string[] exportContents) Assert.Contains("exportnamespace.models.microsoft.graph.User::|public|setOtherNames(value?:java.util.List):void", exportContents);// captures collection info in language specific format } - private static void ValidateExportGo(string[] exportContents) + private static void ValidateExportGo(HashSet exportContents) { Assert.NotEmpty(exportContents); Assert.Contains("exportNamespace.Graph-->*i2ae4187f7daee263371cb1c977df639813ab50ffa529013b7437480d1ec0158f.BaseRequestBuilder", exportContents); // captures class inheritance @@ -178,7 +178,7 @@ private static void ValidateExportGo(string[] exportContents) Assert.Contains("exportNamespace.models.microsoft.graph.user::|public|SetOtherNames(value:[]string):void", exportContents);// captures collection info in language specific format } - private static void ValidateExportPython(string[] exportContents) + private static void ValidateExportPython(HashSet exportContents) { Assert.NotEmpty(exportContents); Assert.Contains("exportNamespace.Graph-->BaseRequestBuilder", exportContents); // captures class inheritance @@ -193,7 +193,7 @@ private static void ValidateExportPython(string[] exportContents) Assert.Contains("exportNamespace.models.microsoft.graph.User::|public|other_names(value:List[str]):None", exportContents);// captures collection info in language specific format } - private static void ValidateExportTypeScript(string[] exportContents) + private static void ValidateExportTypeScript(HashSet exportContents) { Assert.NotEmpty(exportContents); Assert.Contains("exportNamespace.Graph~~>BaseRequestBuilder", exportContents); // captures class inheritance. TS does not do inheritance due to interfaces. @@ -210,7 +210,7 @@ private static void ValidateExportTypeScript(string[] exportContents) Assert.Contains("exportNamespace.models.microsoft.graph.User::|public|otherNames:string[]", exportContents);// captures collection info in language specific format } - private static void ValidateExportPhp(string[] exportContents) + private static void ValidateExportPhp(HashSet exportContents) { Assert.NotEmpty(exportContents); Assert.Contains("exportNamespace.Graph-->BaseRequestBuilder", exportContents); // captures class inheritance diff --git a/tests/Kiota.Builder.Tests/Extensions/OpenApiSchemaExtensionsTests.cs b/tests/Kiota.Builder.Tests/Extensions/OpenApiSchemaExtensionsTests.cs index 6ca611be28..c059dc0234 100644 --- a/tests/Kiota.Builder.Tests/Extensions/OpenApiSchemaExtensionsTests.cs +++ b/tests/Kiota.Builder.Tests/Extensions/OpenApiSchemaExtensionsTests.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; - +using System.Text.Json.Nodes; using Kiota.Builder.Extensions; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; @@ -49,8 +49,8 @@ public void Defensive() Assert.Null(OpenApiSchemaExtensions.MergeIntersectionSchemaEntries(null)); Assert.False(new OpenApiSchema { Reference = null }.IsReferencedSchema()); - Assert.False(new OpenApiSchema { Type = null }.IsArray()); - Assert.False(new OpenApiSchema { Type = null }.IsObjectType()); + Assert.False(new OpenApiSchema { Type = JsonSchemaType.Null }.IsArray()); + Assert.False(new OpenApiSchema { Type = JsonSchemaType.Null }.IsObjectType()); Assert.False(new OpenApiSchema { AnyOf = null }.IsInclusiveUnion()); Assert.False(new OpenApiSchema { AllOf = null }.IsInherited()); Assert.False(new OpenApiSchema { AllOf = null }.IsIntersection()); @@ -486,7 +486,7 @@ public void IsInherited() { AllOf = new List { new() { - Type = "object", + Type = JsonSchemaType.Object, Reference = new() { Id = "microsoft.graph.entity" }, @@ -495,7 +495,7 @@ public void IsInherited() } }, new() { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary() { ["firstName"] = new OpenApiSchema() } @@ -512,7 +512,7 @@ public void IsIntersection() { AllOf = new List { new() { - Type = "object", + Type = JsonSchemaType.Object, Reference = new() { Id = "microsoft.graph.entity" }, @@ -521,7 +521,7 @@ public void IsIntersection() } }, new() { - Type = "object", + Type = JsonSchemaType.Object, Reference = new() { Id = "microsoft.graph.user" }, @@ -538,13 +538,13 @@ public void IsIntersection() { AllOf = new List { new() { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary() { ["id"] = new OpenApiSchema() } }, new() { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary() { ["firstName"] = new OpenApiSchema() } @@ -558,7 +558,7 @@ public void IsIntersection() { AllOf = new List { new() { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary() { ["id"] = new OpenApiSchema() } @@ -576,9 +576,9 @@ public void IsIntersection() { Title = "UserId", Description = "unique identifier", - Type = "string", + Type = JsonSchemaType.String, Pattern = "^[1-9][0-9]*$", - Example = new OpenApiString("1323232"), + Example = "1323232", Reference = new OpenApiReference { Id = "UserId" // This property makes the schema "meaningful" @@ -603,7 +603,7 @@ public void MergesIntersection() Deprecated = true, AllOf = new List { new() { - Type = "object", + Type = JsonSchemaType.Object, Reference = new() { Id = "microsoft.graph.entity" }, @@ -612,7 +612,7 @@ public void MergesIntersection() } }, new() { - Type = "object", + Type = JsonSchemaType.Object, Reference = new() { Id = "microsoft.graph.user" }, @@ -639,23 +639,23 @@ public void MergesIntersectionRecursively() Deprecated = true, AllOf = new List { new() { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary() { ["id"] = new OpenApiSchema() } }, new() { - Type = "object", + Type = JsonSchemaType.Object, AllOf = new List() { new () { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary() { ["firstName"] = new OpenApiSchema(), ["lastName"] = new OpenApiSchema() } }, new () { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary() { ["lastName"] = new OpenApiSchema() } @@ -678,7 +678,7 @@ public void IsArrayFalseOnEmptyItems() { var schema = new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = new OpenApiSchema(), }; Assert.False(schema.IsArray()); @@ -688,7 +688,7 @@ public void IsArrayFalseOnNullItems() { var schema = new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, }; Assert.False(schema.IsArray()); } @@ -697,27 +697,27 @@ public void IsEnumFailsOnEmptyMembers() { var schema = new OpenApiSchema { - Type = "string", - Enum = new List(), + Type = JsonSchemaType.String, + Enum = new List(), }; Assert.False(schema.IsEnum()); - schema.Enum.Add(new OpenApiString("")); + schema.Enum.Add(""); Assert.False(schema.IsEnum()); } private static readonly OpenApiSchema enumSchema = new OpenApiSchema { Title = "riskLevel", - Enum = new List + Enum = new List { - new OpenApiString("low"), - new OpenApiString("medium"), - new OpenApiString("high"), - new OpenApiString("hidden"), - new OpenApiString("none"), - new OpenApiString("unknownFutureValue") - }, - Type = "string" + "low", + "medium", + "high", + "hidden", + "none", + "unknownFutureValue" + }, + Type = JsonSchemaType.String }; [Fact] public void IsEnumIgnoresNullableUnions() @@ -729,7 +729,7 @@ public void IsEnumIgnoresNullableUnions() enumSchema, new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Nullable = true } } @@ -746,7 +746,7 @@ public void IsEnumFailsOnNullableInheritance() enumSchema, new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Nullable = true } } @@ -763,7 +763,7 @@ public void IsEnumIgnoresNullableExclusiveUnions() enumSchema, new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Nullable = true } } @@ -772,7 +772,7 @@ public void IsEnumIgnoresNullableExclusiveUnions() } private static readonly OpenApiSchema numberSchema = new OpenApiSchema { - Type = "number", + Type = JsonSchemaType.Number, Format = "double", }; [Fact] @@ -786,7 +786,7 @@ public void IsEnumDoesNotMaskExclusiveUnions() numberSchema, new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Nullable = true } } @@ -804,7 +804,7 @@ public void IsEnumDoesNotMaskUnions() numberSchema, new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Nullable = true } } @@ -820,24 +820,24 @@ public void IsOdataPrimitive() { new () { - Type = "number", + Type = JsonSchemaType.Number, Format = "double", Nullable = true }, new () { - Type = "string", + Type = JsonSchemaType.String, Nullable = true }, new () { - Enum = new List() + Enum = new List { - new OpenApiString("INF"), - new OpenApiString("INF"), - new OpenApiString("NaN"), + "INF", + "INF", + "NaN", }, - Type = "string", + Type = JsonSchemaType.String, Nullable = true } } @@ -853,20 +853,20 @@ public void IsOdataPrimitiveBackwardCompatible() { new () { - Type = "number", + Type = JsonSchemaType.Number, Format = "double", }, new () { - Type = "string", + Type = JsonSchemaType.String, }, new () { - Enum = new List() + Enum = new List() { - new OpenApiString("INF"), - new OpenApiString("INF"), - new OpenApiString("NaN"), + "INF", + "INF", + "NaN", } } } @@ -904,7 +904,7 @@ public void ReturnsEmptyPropertyNameOnCircularReferences() entitySchema, new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { ["firstName"] = new OpenApiSchema diff --git a/tests/Kiota.Builder.Tests/Extensions/OpenApiUrlTreeNodeExtensionsTests.cs b/tests/Kiota.Builder.Tests/Extensions/OpenApiUrlTreeNodeExtensionsTests.cs index 718248ee2f..0a073478b1 100644 --- a/tests/Kiota.Builder.Tests/Extensions/OpenApiUrlTreeNodeExtensionsTests.cs +++ b/tests/Kiota.Builder.Tests/Extensions/OpenApiUrlTreeNodeExtensionsTests.cs @@ -145,7 +145,7 @@ public void GetUrlTemplateSelectsDistinctQueryParameters() In = ParameterLocation.Path, Required = true, Schema = new() { - Type = "string" + Type = JsonSchemaType.String }, Style = ParameterStyle.Simple, }, @@ -153,7 +153,7 @@ public void GetUrlTemplateSelectsDistinctQueryParameters() Name = "$select", In = ParameterLocation.Query, Schema = new () { - Type = "string" + Type = JsonSchemaType.String }, Style = ParameterStyle.Simple, } @@ -168,7 +168,7 @@ public void GetUrlTemplateSelectsDistinctQueryParameters() In = ParameterLocation.Path, Required = true, Schema = new() { - Type = "string" + Type = JsonSchemaType.String }, Style = ParameterStyle.Simple, }, @@ -176,7 +176,7 @@ public void GetUrlTemplateSelectsDistinctQueryParameters() Name = "$select", In = ParameterLocation.Query, Schema = new () { - Type = "string" + Type = JsonSchemaType.String }, Style = ParameterStyle.Simple, } @@ -206,7 +206,7 @@ public void DifferentUrlTemplatesPerOperation() Required = true, Schema = new() { - Type = "string" + Type = JsonSchemaType.String }, Style = ParameterStyle.Simple, }, @@ -219,7 +219,7 @@ public void DifferentUrlTemplatesPerOperation() Name = "$select", In = ParameterLocation.Query, Schema = new () { - Type = "string" + Type = JsonSchemaType.String }, Style = ParameterStyle.Simple, } @@ -256,7 +256,7 @@ public void DifferentUrlTemplatesPerOperationWithRequiredParameter() Required = true, Schema = new() { - Type = "string" + Type = JsonSchemaType.String }, Style = ParameterStyle.Simple, }, @@ -269,7 +269,7 @@ public void DifferentUrlTemplatesPerOperationWithRequiredParameter() Name = "$select", In = ParameterLocation.Query, Schema = new () { - Type = "string" + Type = JsonSchemaType.String }, Style = ParameterStyle.Simple, } @@ -283,7 +283,7 @@ public void DifferentUrlTemplatesPerOperationWithRequiredParameter() Name = "$expand", In = ParameterLocation.Query, Schema = new () { - Type = "string" + Type = JsonSchemaType.String }, Style = ParameterStyle.Simple, } @@ -300,7 +300,7 @@ public void DifferentUrlTemplatesPerOperationWithRequiredParameter() Name = "id", In = ParameterLocation.Query, Schema = new () { - Type = "string" + Type = JsonSchemaType.String }, Style = ParameterStyle.Simple, Required = true @@ -335,7 +335,7 @@ public void GeneratesRequiredQueryParametersAndOptionalMixInPathItem() In = ParameterLocation.Path, Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, new OpenApiParameter { @@ -343,7 +343,7 @@ public void GeneratesRequiredQueryParametersAndOptionalMixInPathItem() In = ParameterLocation.Query, Required = false, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, new OpenApiParameter { @@ -351,7 +351,7 @@ public void GeneratesRequiredQueryParametersAndOptionalMixInPathItem() In = ParameterLocation.Query, Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -381,7 +381,7 @@ public void GeneratesRequiredQueryParametersAndOptionalMixInOperation() In = ParameterLocation.Path, Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, new OpenApiParameter { @@ -389,7 +389,7 @@ public void GeneratesRequiredQueryParametersAndOptionalMixInOperation() In = ParameterLocation.Query, Required = false, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, new OpenApiParameter { @@ -397,7 +397,7 @@ public void GeneratesRequiredQueryParametersAndOptionalMixInOperation() In = ParameterLocation.Query, Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -423,7 +423,7 @@ public void GeneratesOnlyOptionalQueryParametersInPathItem() In = ParameterLocation.Path, Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, new OpenApiParameter { @@ -431,14 +431,14 @@ public void GeneratesOnlyOptionalQueryParametersInPathItem() In = ParameterLocation.Query, Required = false, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, new OpenApiParameter { Name = "apikey", In = ParameterLocation.Query, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -468,21 +468,21 @@ public void GeneratesOnlyOptionalQueryParametersInOperation() In = ParameterLocation.Path, Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, new OpenApiParameter { Name = "filter", In = ParameterLocation.Query, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, new OpenApiParameter { Name = "apikey", In = ParameterLocation.Query, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -508,7 +508,7 @@ public void GeneratesOnlyRequiredQueryParametersInPathItem() In = ParameterLocation.Path, Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, new OpenApiParameter { @@ -516,7 +516,7 @@ public void GeneratesOnlyRequiredQueryParametersInPathItem() In = ParameterLocation.Query, Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, new OpenApiParameter { @@ -524,7 +524,7 @@ public void GeneratesOnlyRequiredQueryParametersInPathItem() Required = true, In = ParameterLocation.Query, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -554,7 +554,7 @@ public void GeneratesOnlyRequiredQueryParametersInOperation() In = ParameterLocation.Path, Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, new OpenApiParameter { @@ -562,7 +562,7 @@ public void GeneratesOnlyRequiredQueryParametersInOperation() Required = true, In = ParameterLocation.Query, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, new OpenApiParameter { @@ -570,7 +570,7 @@ public void GeneratesOnlyRequiredQueryParametersInOperation() Required = true, In = ParameterLocation.Query, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -599,7 +599,7 @@ public void GetUrlTemplateCleansInvalidParameters() In = ParameterLocation.Path, Required = true, Schema = new() { - Type = "string" + Type = JsonSchemaType.String }, Style = ParameterStyle.Simple, }, @@ -607,7 +607,7 @@ public void GetUrlTemplateCleansInvalidParameters() Name = "$select", In = ParameterLocation.Query, Schema = new () { - Type = "string" + Type = JsonSchemaType.String }, Style = ParameterStyle.Simple, }, @@ -615,7 +615,7 @@ public void GetUrlTemplateCleansInvalidParameters() Name = "api-version", In = ParameterLocation.Query, Schema = new () { - Type = "string" + Type = JsonSchemaType.String }, Style = ParameterStyle.Simple, }, @@ -623,7 +623,7 @@ public void GetUrlTemplateCleansInvalidParameters() Name = "api~topic", In = ParameterLocation.Query, Schema = new () { - Type = "string" + Type = JsonSchemaType.String }, Style = ParameterStyle.Simple, }, @@ -631,7 +631,7 @@ public void GetUrlTemplateCleansInvalidParameters() Name = "api.encoding", In = ParameterLocation.Query, Schema = new () { - Type = "string" + Type = JsonSchemaType.String }, Style = ParameterStyle.Simple, } @@ -669,7 +669,7 @@ public void GetsClassNameWithIndexerAndExtension() In = ParameterLocation.Path, Required = true, Schema = new() { - Type = "string" + Type = JsonSchemaType.String }, Style = ParameterStyle.Simple, } @@ -679,7 +679,7 @@ public void GetsClassNameWithIndexerAndExtension() Content = new Dictionary() { {"application/json", new() { Schema = new () { - Type = "string" + Type = JsonSchemaType.String } }} } @@ -711,7 +711,7 @@ public void GetsClassNameWithSegmentsToSkipForClassNames() In = ParameterLocation.Path, Required = true, Schema = new() { - Type = "string" + Type = JsonSchemaType.String }, Style = ParameterStyle.Simple, } @@ -728,7 +728,7 @@ public void GetsClassNameWithSegmentsToSkipForClassNames() { Schema = new () { - Type = "object", + Type = JsonSchemaType.Object, Title = "json", Reference = new OpenApiReference() { @@ -763,16 +763,16 @@ public void SinglePathParametersAreDeduplicated() { var userSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, { "displayName", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -794,7 +794,7 @@ public void SinglePathParametersAreDeduplicated() In = ParameterLocation.Path, Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, }, @@ -823,7 +823,7 @@ public void SinglePathParametersAreDeduplicated() In = ParameterLocation.Path, Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, }, @@ -855,7 +855,7 @@ public void SinglePathParametersAreDeduplicated() In = ParameterLocation.Path, Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, }, @@ -912,11 +912,11 @@ public void SinglePathParametersAreDeduplicatedAndOrderIsRespected() { var ownerSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -928,11 +928,11 @@ public void SinglePathParametersAreDeduplicatedAndOrderIsRespected() }; var repoSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -1023,7 +1023,7 @@ public void repro4085() ["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } } @@ -1044,7 +1044,7 @@ public void repro4085() ["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } } diff --git a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs index a62089926f..88b05cd08c 100644 --- a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs +++ b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Net.Http; using System.Text; +using System.Text.Json.Nodes; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; @@ -426,7 +427,7 @@ public async Task ParsesEnumDescriptionsAsync() StorageAccountType: type: string enum: - - +1 + - '+1' - -1 - Standard_LRS - Standard_ZRS @@ -438,7 +439,7 @@ public async Task ParsesEnumDescriptionsAsync() name: AccountType modelAsString: false values: - - value: +1 + - value: '+1' - value: -1 - value: Standard_LRS description: Locally redundant storage. @@ -1354,10 +1355,10 @@ public void Single_path_with_get_collection() { Schema = new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = new OpenApiSchema { - Type = "int" + Type = JsonSchemaType.Integer } } } @@ -1399,19 +1400,19 @@ public void OData_doubles_as_one_of() { Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "progress", new OpenApiSchema{ OneOf = new List{ new OpenApiSchema{ - Type = "number" + Type = JsonSchemaType.Number }, new OpenApiSchema{ - Type = "string" + Type = JsonSchemaType.String }, new OpenApiSchema { - Enum = new List { new OpenApiString("-INF"), new OpenApiString("INF"), new OpenApiString("NaN") } + Enum = new List { "-INF", "INF", "NaN" } } }, Format = "double" @@ -1451,20 +1452,20 @@ public void OData_doubles_as_one_of_format_inside() { Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "progress", new OpenApiSchema{ OneOf = new List{ new OpenApiSchema{ - Type = "number", + Type = JsonSchemaType.Number, Format = "double" }, new OpenApiSchema{ - Type = "string" + Type = JsonSchemaType.String }, new OpenApiSchema { - Enum = new List { new OpenApiString("-INF"), new OpenApiString("INF"), new OpenApiString("NaN") } + Enum = new List { "-INF", "INF", "NaN" } } }, } @@ -1503,19 +1504,19 @@ public void OData_doubles_as_any_of() { Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "progress", new OpenApiSchema{ AnyOf = new List{ new OpenApiSchema{ - Type = "number" + Type = JsonSchemaType.Number }, new OpenApiSchema{ - Type = "string" + Type = JsonSchemaType.String }, new OpenApiSchema { - Enum = new List { new OpenApiString("-INF"), new OpenApiString("INF"), new OpenApiString("NaN") } + Enum = new List { "-INF", "INF", "NaN" } } }, Format = "double" @@ -1541,15 +1542,15 @@ public void MultiNestedArraysSupportedAsUntypedNodes() { var fooSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "sortBy", new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } } @@ -1609,16 +1610,16 @@ public void Object_Arrays_are_supported() { var userSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, { "displayName", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -1644,17 +1645,17 @@ public void Object_Arrays_are_supported() ["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "value", new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = userSchema } }, { "unknown", new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = new OpenApiSchema { } } @@ -1711,7 +1712,7 @@ public void TextPlainEndpointsAreSupported() ["text/plain"] = new OpenApiMediaType { Schema = new OpenApiSchema { - Type = "number", + Type = JsonSchemaType.Number, Format = "int32", } } @@ -1740,22 +1741,22 @@ public void Supports_Path_Parameters() { var resourceActionSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Title = "resourceAction", Properties = new Dictionary { { "allowedResourceActions", new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, { "notAllowedResourceActions", new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } } @@ -1768,11 +1769,11 @@ public void Supports_Path_Parameters() }; var permissionSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "resourceActions", new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = new OpenApiSchema { AnyOf = new List { resourceActionSchema, @@ -1800,7 +1801,7 @@ public void Supports_Path_Parameters() In = ParameterLocation.Path, Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -1814,7 +1815,7 @@ public void Supports_Path_Parameters() ["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = new OpenApiSchema { AnyOf = new List { permissionSchema, @@ -1861,22 +1862,22 @@ public void Supports_Path_Query_And_Header_Parameters() { var resourceActionSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Title = "resourceAction", Properties = new Dictionary { { "allowedResourceActions", new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, { "notAllowedResourceActions", new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } } @@ -1889,11 +1890,11 @@ public void Supports_Path_Query_And_Header_Parameters() }; var permissionSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "resourceActions", new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = new OpenApiSchema { AnyOf = new List { resourceActionSchema, @@ -1921,7 +1922,7 @@ public void Supports_Path_Query_And_Header_Parameters() In = ParameterLocation.Path, Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, new OpenApiParameter @@ -1930,7 +1931,7 @@ public void Supports_Path_Query_And_Header_Parameters() In = ParameterLocation.Query, Required = false, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String }, }, new OpenApiParameter @@ -1940,7 +1941,7 @@ public void Supports_Path_Query_And_Header_Parameters() Description = "ETag", Required = false, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String }, }, new OpenApiParameter @@ -1950,7 +1951,7 @@ public void Supports_Path_Query_And_Header_Parameters() Description = "Consistency level", Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String }, } }, @@ -1964,7 +1965,7 @@ public void Supports_Path_Query_And_Header_Parameters() ["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = new OpenApiSchema { AnyOf = new List { permissionSchema, @@ -2031,7 +2032,7 @@ public void DeduplicatesConflictingParameterNamesForCLI() In = ParameterLocation.Path, Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, new OpenApiParameter @@ -2040,7 +2041,7 @@ public void DeduplicatesConflictingParameterNamesForCLI() In = ParameterLocation.Query, Required = false, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String }, }, new OpenApiParameter @@ -2049,7 +2050,7 @@ public void DeduplicatesConflictingParameterNamesForCLI() In = ParameterLocation.Header, Required = false, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String }, }, }, @@ -2063,10 +2064,10 @@ public void DeduplicatesConflictingParameterNamesForCLI() ["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary() { { "foo", new() { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -2105,11 +2106,11 @@ public void Inline_Property_Inheritance_Is_Supported() { var resourceSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "info", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -2135,19 +2136,19 @@ public void Inline_Property_Inheritance_Is_Supported() ["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "derivedResource", new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "info2", new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "title", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } } @@ -2203,7 +2204,7 @@ public void Inline_Property_Inheritance_Is_Supported2() { var resourceSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Reference = new OpenApiReference { Id = "resource" @@ -2213,7 +2214,7 @@ public void Inline_Property_Inheritance_Is_Supported2() var properties = new Dictionary { - { "info", new OpenApiSchema { Type = "string", } }, + { "info", new OpenApiSchema { Type = JsonSchemaType.String, } }, { "derivedResource", new OpenApiSchema { AllOf = new List { resourceSchema, } } }, }; @@ -2289,11 +2290,11 @@ public void MapsTime() { Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "progress", new OpenApiSchema{ - Type = "string", + Type = JsonSchemaType.String, Format = "time" } } @@ -2331,11 +2332,11 @@ public void MapsDate() { Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "progress", new OpenApiSchema{ - Type = "string", + Type = JsonSchemaType.String, Format = "date" } } @@ -2373,11 +2374,11 @@ public void MapsDuration() { Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "progress", new OpenApiSchema{ - Type = "string", + Type = JsonSchemaType.String, Format = "duration" } } @@ -2415,11 +2416,11 @@ public void AddsErrorMapping() { Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "progress", new OpenApiSchema{ - Type = "string", + Type = JsonSchemaType.String, } } } @@ -2435,11 +2436,11 @@ public void AddsErrorMapping() { Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "errorId", new OpenApiSchema{ - Type = "string", + Type = JsonSchemaType.String, Extensions = new Dictionary { { OpenApiPrimaryErrorMessageExtension.Name, @@ -2463,11 +2464,11 @@ public void AddsErrorMapping() { Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "serviceErrorId", new OpenApiSchema{ - Type = "string", + Type = JsonSchemaType.String, Extensions = new Dictionary { { OpenApiPrimaryErrorMessageExtension.Name, @@ -2491,7 +2492,7 @@ public void AddsErrorMapping() { Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } } @@ -2504,11 +2505,11 @@ public void AddsErrorMapping() { Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "authenticationRealm", new OpenApiSchema{ - Type = "string", + Type = JsonSchemaType.String, Extensions = new Dictionary { { OpenApiPrimaryErrorMessageExtension.Name, @@ -2521,7 +2522,7 @@ public void AddsErrorMapping() }, { "authenticationCode", new OpenApiSchema{ - Type = "string", + Type = JsonSchemaType.String, } } } @@ -2585,11 +2586,11 @@ public void IgnoresErrorCodesWithNoSchema() { Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "progress", new OpenApiSchema{ - Type = "string", + Type = JsonSchemaType.String, } } } @@ -2634,11 +2635,11 @@ public void DoesntAddSuffixesToErrorTypesWhenComponents() { var errorSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "errorId", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -2684,11 +2685,11 @@ public void DoesntAddSuffixesToErrorTypesWhenComponents() { Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "progress", new OpenApiSchema{ - Type = "string", + Type = JsonSchemaType.String, } } } @@ -2744,11 +2745,11 @@ public void UsesDefaultAs4XXAnd5XXWhenAbsent() { var errorSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "errorId", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -2794,11 +2795,11 @@ public void UsesDefaultAs4XXAnd5XXWhenAbsent() { Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "progress", new OpenApiSchema{ - Type = "string", + Type = JsonSchemaType.String, } } } @@ -2853,18 +2854,18 @@ public void DoesntAddPropertyHolderOnNonAdditionalModels() { var weatherForecastSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, AdditionalPropertiesAllowed = false, Properties = new Dictionary { { "date", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, Format = "date-time" } }, { "temperature", new OpenApiSchema { - Type = "integer", + Type = JsonSchemaType.Integer, Format = "int32" } } @@ -2938,18 +2939,18 @@ public void SquishesLonelyNullables() { var uploadSessionSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, AdditionalPropertiesAllowed = false, Properties = new Dictionary { { "date", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, Format = "date-time" } }, { "temperature", new OpenApiSchema { - Type = "integer", + Type = JsonSchemaType.Integer, Format = "int32" } } @@ -3022,18 +3023,18 @@ public void SquishesLonelyNullablesBothAnyOf() { var uploadSessionSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, AdditionalPropertiesAllowed = false, Properties = new Dictionary { { "date", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, Format = "date-time" } }, { "temperature", new OpenApiSchema { - Type = "integer", + Type = JsonSchemaType.Integer, Format = "int32" } } @@ -3108,19 +3109,19 @@ public void SupportsArraysInComposedTypes() { var anyOfSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, AdditionalPropertiesAllowed = false, Properties = new Dictionary { { "date", new OpenApiSchema { AnyOf = [ new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, }, new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, }, }, ] @@ -3191,18 +3192,18 @@ public void SupportsNullableAnyOf() { var anyOfSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, AdditionalPropertiesAllowed = false, Properties = new Dictionary { { "date", new OpenApiSchema { AnyOf = [ new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, Nullable = true }, new OpenApiSchema { - Type = "number", + Type = JsonSchemaType.Number, Format = "int64", Nullable = true, } @@ -3275,17 +3276,17 @@ public void AddsDiscriminatorMappings() { var entitySchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, { "@odata.type", new OpenApiSchema { - Type = "string", - Default = new OpenApiString("#microsoft.graph.entity") + Type = JsonSchemaType.String, + Default = "#microsoft.graph.entity" } } }, @@ -3310,16 +3311,16 @@ public void AddsDiscriminatorMappings() }; var directoryObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "tenant", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, { "@odata.type", new OpenApiSchema { - Type = "string", - Default = new OpenApiString("#microsoft.graph.directoryObject") + Type = JsonSchemaType.String, + Default = "#microsoft.graph.directoryObject" } } }, @@ -3410,17 +3411,17 @@ public void DoesntAddDiscriminatorMappingsOfNonDerivedTypes() { var entitySchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, { "@odata.type", new OpenApiSchema { - Type = "string", - Default = new OpenApiString("#microsoft.graph.entity") + Type = JsonSchemaType.String, + Default = "#microsoft.graph.entity" } } }, @@ -3448,16 +3449,16 @@ public void DoesntAddDiscriminatorMappingsOfNonDerivedTypes() }; var directoryObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "tenant", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, { "@odata.type", new OpenApiSchema { - Type = "string", - Default = new OpenApiString("#microsoft.graph.directoryObject") + Type = JsonSchemaType.String, + Default = "#microsoft.graph.directoryObject" } } }, @@ -3473,16 +3474,16 @@ public void DoesntAddDiscriminatorMappingsOfNonDerivedTypes() }; var fileSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "tenant", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, { "@odata.type", new OpenApiSchema { - Type = "string", - Default = new OpenApiString("#microsoft.graph.file") + Type = JsonSchemaType.String, + Default = "#microsoft.graph.file" } } }, @@ -3562,17 +3563,17 @@ public async Task AddsDiscriminatorMappingsOneOfImplicitAsync() { var entitySchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, { "@odata.type", new OpenApiSchema { - Type = "string", - Default = new OpenApiString("microsoft.graph.entity") + Type = JsonSchemaType.String, + Default = "microsoft.graph.entity" } } }, @@ -3592,16 +3593,16 @@ public async Task AddsDiscriminatorMappingsOneOfImplicitAsync() }; var directoryObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "tenant", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, { "@odata.type", new OpenApiSchema { - Type = "string", - Default = new OpenApiString("microsoft.graph.directoryObject") + Type = JsonSchemaType.String, + Default = "microsoft.graph.directoryObject" } } }, @@ -3617,7 +3618,7 @@ public async Task AddsDiscriminatorMappingsOneOfImplicitAsync() }; var directoryObjectsResponse = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, OneOf = new List { entitySchema, directoryObjectSchema @@ -3705,17 +3706,17 @@ public async Task AddsDiscriminatorMappingsAllOfImplicitAsync() { var entitySchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, { "@odata.type", new OpenApiSchema { - Type = "string", - Default = new OpenApiString("#microsoft.graph.entity") + Type = JsonSchemaType.String, + Default = "#microsoft.graph.entity" } } }, @@ -3735,19 +3736,19 @@ public async Task AddsDiscriminatorMappingsAllOfImplicitAsync() }; var directoryObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, AllOf = new List { entitySchema, new OpenApiSchema { Properties = new Dictionary { { "tenant", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, { "@odata.type", new OpenApiSchema { - Type = "string", - Default = new OpenApiString("microsoft.graph.directoryObject") + Type = JsonSchemaType.String, + Default = "microsoft.graph.directoryObject" } } }, @@ -3765,19 +3766,19 @@ public async Task AddsDiscriminatorMappingsAllOfImplicitAsync() }; var userSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, AllOf = new List { directoryObjectSchema, new OpenApiSchema { Properties = new Dictionary { { "firstName", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, { "@odata.type", new OpenApiSchema { - Type = "string", - Default = new OpenApiString("microsoft.graph.firstName") + Type = JsonSchemaType.String, + Default = "microsoft.graph.firstName" } } }, @@ -3883,17 +3884,17 @@ public async Task AddsDiscriminatorMappingsAllOfImplicitWithParentHavingMappings { var entitySchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, { "@odata.type", new OpenApiSchema { - Type = "string", - Default = new OpenApiString("#microsoft.graph.entity") + Type = JsonSchemaType.String, + Default = "#microsoft.graph.entity" } } }, @@ -3922,7 +3923,7 @@ public async Task AddsDiscriminatorMappingsAllOfImplicitWithParentHavingMappings }; var directoryObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, AllOf = [ entitySchema, new OpenApiSchema @@ -3930,12 +3931,12 @@ public async Task AddsDiscriminatorMappingsAllOfImplicitWithParentHavingMappings Properties = new Dictionary { { "tenant", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, { "@odata.type", new OpenApiSchema { - Type = "string", - Default = new OpenApiString("microsoft.graph.directoryObject") + Type = JsonSchemaType.String, + Default = "microsoft.graph.directoryObject" } } }, @@ -3953,7 +3954,7 @@ public async Task AddsDiscriminatorMappingsAllOfImplicitWithParentHavingMappings }; var userSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, AllOf = [ directoryObjectSchema, new OpenApiSchema @@ -3961,12 +3962,12 @@ public async Task AddsDiscriminatorMappingsAllOfImplicitWithParentHavingMappings Properties = new Dictionary { { "firstName", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, { "@odata.type", new OpenApiSchema { - Type = "string", - Default = new OpenApiString("microsoft.graph.firstName") + Type = JsonSchemaType.String, + Default = "microsoft.graph.firstName" } } }, @@ -4064,11 +4065,11 @@ public void UnionOfPrimitiveTypesWorks() { var simpleObjet = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -4097,7 +4098,7 @@ public void UnionOfPrimitiveTypesWorks() OneOf = new List { simpleObjet, new OpenApiSchema { - Type = "number" + Type = JsonSchemaType.Number } } } @@ -4182,11 +4183,11 @@ public void UnionOfInlineSchemasWorks() { var simpleObjet = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -4215,11 +4216,11 @@ public void UnionOfInlineSchemasWorks() OneOf = new List { simpleObjet, new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } } @@ -4265,11 +4266,11 @@ public void IntersectionOfPrimitiveTypesWorks() { var simpleObjet = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -4298,7 +4299,7 @@ public void IntersectionOfPrimitiveTypesWorks() AnyOf = new List { simpleObjet, new OpenApiSchema { - Type = "number" + Type = JsonSchemaType.Number } } } @@ -4341,11 +4342,11 @@ public void IntersectionOfInlineSchemasWorks() { var simpleObjet = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -4374,11 +4375,11 @@ public void IntersectionOfInlineSchemasWorks() AnyOf = new List { simpleObjet, new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } } @@ -4424,16 +4425,16 @@ public void InheritedTypeWithInlineSchemaWorks() { var baseObject = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, { "kind", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -4455,16 +4456,16 @@ public void InheritedTypeWithInlineSchemaWorks() }; var derivedObject = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, AllOf = [ baseObject, new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "special", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -4488,16 +4489,16 @@ public void InheritedTypeWithInlineSchemaWorks() }; var secondLevelDerivedObject = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, AllOf = [ derivedObject, new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "moreSpecial", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } } @@ -4568,38 +4569,37 @@ public void InheritedTypeWithInlineSchemaWorks() Assert.Equal("kind", derivedObjectClass.DiscriminatorInformation.DiscriminatorPropertyName); Assert.NotEmpty(derivedObjectClass.DiscriminatorInformation.DiscriminatorMappings); } - [InlineData("string", "", "string")]// https://spec.openapis.org/registry/format/ - [InlineData("string", "commonmark", "string")] - [InlineData("string", "html", "string")] - [InlineData("string", "date-time", "DateTimeOffset")] - [InlineData("string", "duration", "TimeSpan")] - [InlineData("string", "date", "DateOnly")] - [InlineData("string", "time", "TimeOnly")] - [InlineData("string", "base64url", "base64url")] - [InlineData("string", "uuid", "Guid")] + [InlineData(JsonSchemaType.String, "", "string")]// https://spec.openapis.org/registry/format/ + [InlineData(JsonSchemaType.String, "commonmark", "string")] + [InlineData(JsonSchemaType.String, "html", "string")] + [InlineData(JsonSchemaType.String, "date-time", "DateTimeOffset")] + [InlineData(JsonSchemaType.String, "duration", "TimeSpan")] + [InlineData(JsonSchemaType.String, "date", "DateOnly")] + [InlineData(JsonSchemaType.String, "time", "TimeOnly")] + [InlineData(JsonSchemaType.String, "base64url", "base64url")] + [InlineData(JsonSchemaType.String, "uuid", "Guid")] // floating points can only be declared as numbers - [InlineData("number", "double", "double")] - [InlineData("number", "float", "float")] - [InlineData("number", "decimal", "decimal")] + [InlineData(JsonSchemaType.Number, "double", "double")] + [InlineData(JsonSchemaType.Number, "float", "float")] + [InlineData(JsonSchemaType.Number, "decimal", "decimal")] // integers can only be declared as numbers or integers - [InlineData("number", "int32", "integer")] - [InlineData("integer", "int32", "integer")] - [InlineData("number", "int64", "int64")] - [InlineData("integer", "int64", "int64")] - [InlineData("number", "int8", "sbyte")] - [InlineData("integer", "int8", "sbyte")] - [InlineData("number", "int16", "integer")] - [InlineData("integer", "int16", "integer")] - [InlineData("number", "uint8", "byte")] - [InlineData("integer", "uint8", "byte")] - [InlineData("number", "", "double")] - [InlineData("integer", "", "integer")] - [InlineData("boolean", "", "boolean")] - [InlineData("", "byte", "base64")] - [InlineData("", "binary", "binary")] - [InlineData("file", null, "binary")] + [InlineData(JsonSchemaType.Number, "int32", "integer")] + [InlineData(JsonSchemaType.Integer, "int32", "integer")] + [InlineData(JsonSchemaType.Number, "int64", "int64")] + [InlineData(JsonSchemaType.Integer, "int64", "int64")] + [InlineData(JsonSchemaType.Number, "int8", "sbyte")] + [InlineData(JsonSchemaType.Integer, "int8", "sbyte")] + [InlineData(JsonSchemaType.Number, "int16", "integer")] + [InlineData(JsonSchemaType.Integer, "int16", "integer")] + [InlineData(JsonSchemaType.Number, "uint8", "byte")] + [InlineData(JsonSchemaType.Integer, "uint8", "byte")] + [InlineData(JsonSchemaType.Number, "", "double")] + [InlineData(JsonSchemaType.Integer, "", "integer")] + [InlineData(JsonSchemaType.Boolean, "", "boolean")] + [InlineData(JsonSchemaType.String, "byte", "base64")] + [InlineData(JsonSchemaType.String, "binary", "binary")] [Theory] - public void MapsPrimitiveFormats(string type, string format, string expected) + public void MapsPrimitiveFormats(JsonSchemaType type, string format, string expected) { var document = new OpenApiDocument { @@ -4639,35 +4639,34 @@ public void MapsPrimitiveFormats(string type, string format, string expected) Assert.Equal(expected, method.ReturnType.Name); Assert.True(method.ReturnType.AllTypes.First().IsExternal); } - [InlineData("string", "", "string")]// https://spec.openapis.org/registry/format/ - [InlineData("string", "commonmark", "string")] - [InlineData("string", "html", "string")] - [InlineData("string", "date-time", "DateTimeOffset")] - [InlineData("string", "duration", "TimeSpan")] - [InlineData("string", "date", "DateOnly")] - [InlineData("string", "time", "TimeOnly")] - [InlineData("string", "base64url", "base64url")] + [InlineData(JsonSchemaType.String, "", "string")]// https://spec.openapis.org/registry/format/ + [InlineData(JsonSchemaType.String, "commonmark", "string")] + [InlineData(JsonSchemaType.String, "html", "string")] + [InlineData(JsonSchemaType.String, "date-time", "DateTimeOffset")] + [InlineData(JsonSchemaType.String, "duration", "TimeSpan")] + [InlineData(JsonSchemaType.String, "date", "DateOnly")] + [InlineData(JsonSchemaType.String, "time", "TimeOnly")] + [InlineData(JsonSchemaType.String, "base64url", "base64url")] // floating points can only be declared as numbers - [InlineData("number", "double", "double")] - [InlineData("number", "float", "float")] - [InlineData("number", "decimal", "decimal")] + [InlineData(JsonSchemaType.Number, "double", "double")] + [InlineData(JsonSchemaType.Number, "float", "float")] + [InlineData(JsonSchemaType.Number, "decimal", "decimal")] // integers can only be declared as numbers or integers - [InlineData("number", "int32", "integer")] - [InlineData("integer", "int32", "integer")] - [InlineData("number", "int64", "int64")] - [InlineData("integer", "int64", "int64")] - [InlineData("number", "int8", "sbyte")] - [InlineData("integer", "int8", "sbyte")] - [InlineData("number", "uint8", "byte")] - [InlineData("integer", "uint8", "byte")] - [InlineData("number", "", "double")] - [InlineData("integer", "", "integer")] - [InlineData("boolean", "", "boolean")] - [InlineData("", "byte", "base64")] - [InlineData("", "binary", "binary")] - [InlineData("file", null, "binary")] + [InlineData(JsonSchemaType.Number, "int32", "integer")] + [InlineData(JsonSchemaType.Integer, "int32", "integer")] + [InlineData(JsonSchemaType.Number, "int64", "int64")] + [InlineData(JsonSchemaType.Integer, "int64", "int64")] + [InlineData(JsonSchemaType.Number, "int8", "sbyte")] + [InlineData(JsonSchemaType.Integer, "int8", "sbyte")] + [InlineData(JsonSchemaType.Number, "uint8", "byte")] + [InlineData(JsonSchemaType.Integer, "uint8", "byte")] + [InlineData(JsonSchemaType.Number, "", "double")] + [InlineData(JsonSchemaType.Integer, "", "integer")] + [InlineData(JsonSchemaType.Boolean, "", "boolean")] + [InlineData(JsonSchemaType.String, "byte", "base64")] + [InlineData(JsonSchemaType.String, "binary", "binary")] [Theory] - public void MapsQueryParameterTypes(string type, string format, string expected) + public void MapsQueryParameterTypes(JsonSchemaType type, string format, string expected) { var document = new OpenApiDocument { @@ -4725,9 +4724,9 @@ public void MapsQueryParameterArrayTypes() Name = "query", In = ParameterLocation.Query, Schema = new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = new OpenApiSchema { - Type = "integer", + Type = JsonSchemaType.Integer, Format = "int64" } } @@ -4773,10 +4772,10 @@ public void MapsEnumQueryParameterType(GenerationLanguage generationLanguage) Name = "query", In = ParameterLocation.Query, Schema = new OpenApiSchema { - Type = "string", - Enum = new List { - new OpenApiString("value1"), - new OpenApiString("value2") + Type = JsonSchemaType.String, + Enum = new List { + "value1", + "value2" } } } @@ -4883,12 +4882,12 @@ public void MapsQueryParameterCollectionKinds(bool isArray) { var baseSchema = new OpenApiSchema { - Type = "number", + Type = JsonSchemaType.Number, Format = "int64" }; var arraySchema = new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = baseSchema }; var document = new OpenApiDocument @@ -4971,11 +4970,11 @@ public void DoesntGenerateNamespacesWhenNotRequired() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -5034,11 +5033,11 @@ public void GeneratesNamesapacesWhenRequired() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -5097,11 +5096,11 @@ public void IdsResultInIndexers() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -5164,25 +5163,25 @@ public void HandlesCollectionOfEnumSchemasInAnyOfWithNullable() var enumSchema = new OpenApiSchema { Title = "riskLevel", - Enum = new List + Enum = new List { - new OpenApiString("low"), - new OpenApiString("medium"), - new OpenApiString("high"), - new OpenApiString("hidden"), - new OpenApiString("none"), - new OpenApiString("unknownFutureValue") + "low", + "medium", + "high", + "hidden", + "none", + "unknownFutureValue" }, - Type = "string" + Type = JsonSchemaType.String }; var myObjectSchema = new OpenApiSchema { Title = "conditionalAccessConditionSet", - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "signInRiskLevels", new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = new OpenApiSchema { AnyOf = new List @@ -5190,7 +5189,7 @@ public void HandlesCollectionOfEnumSchemasInAnyOfWithNullable() enumSchema, new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Nullable = true } } @@ -5264,25 +5263,25 @@ public void HandlesCollectionOfEnumSchemas() var enumSchema = new OpenApiSchema { Title = "riskLevel", - Enum = new List + Enum = new List { - new OpenApiString("low"), - new OpenApiString("medium"), - new OpenApiString("high"), - new OpenApiString("hidden"), - new OpenApiString("none"), - new OpenApiString("unknownFutureValue") + "low", + "medium", + "high", + "hidden", + "none", + "unknownFutureValue" }, - Type = "string" + Type = JsonSchemaType.String }; var myObjectSchema = new OpenApiSchema { Title = "conditionalAccessConditionSet", - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "signInRiskLevels", new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = enumSchema } } @@ -5352,13 +5351,13 @@ public void InlinePropertiesGenerateTypes() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "tilleggsinformasjon", new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, AdditionalProperties = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } } @@ -5419,11 +5418,11 @@ public void ModelsDoesntUsePathDescriptionWhenAvailable() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -5485,11 +5484,11 @@ public void CleansUpInvalidDescriptionCharacters() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -5553,11 +5552,11 @@ public void AcceptVendorsTypes(string contentType) { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -5640,7 +5639,7 @@ public void ModelsUseDescriptionWhenAvailable(bool excludeBackwardCompatible) Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } } @@ -5693,11 +5692,11 @@ public void Considers200WithSchemaOver2XXWithSchema() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -5710,11 +5709,11 @@ public void Considers200WithSchemaOver2XXWithSchema() }; var myOtherObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -5788,11 +5787,11 @@ public void Considers2XXWithSchemaOver204WithNoSchema() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -5861,11 +5860,11 @@ public void Considers204WithNoSchemaOver206WithNoSchema() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -5934,11 +5933,11 @@ public void DoesntGenerateVoidExecutorOnMixedNoContent(int statusCode) { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -6006,11 +6005,11 @@ public void GeneratesVoidReturnTypeForNoContent(int statusCode) { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -6081,11 +6080,11 @@ public void StripsCommonModelsPrefix(string[] componentNames, string stripPrefix { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -6129,11 +6128,11 @@ public void HandlesContentParameters() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -6162,9 +6161,9 @@ public void HandlesContentParameters() { "application/json", new OpenApiMediaType { Schema = new OpenApiSchema { - Type = "array", + Type = JsonSchemaType.Array, Items = new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } } @@ -6216,11 +6215,11 @@ public void HandlesPagingExtension() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -6285,11 +6284,11 @@ public void SetsReadonlyProperties(bool isReadonly) { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, ReadOnly = isReadonly, } } @@ -6349,11 +6348,11 @@ public void SupportsIncludeFilterOnRootPath(string inputPattern, int expectedPat { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -6414,11 +6413,11 @@ public void SupportsIncludeFilter() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -6499,11 +6498,11 @@ public void SupportsExcludeFilter() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -6584,11 +6583,11 @@ public void SupportsIncludeFilterWithOperation() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -6739,11 +6738,11 @@ public void SupportsIndexingParametersInSubPaths() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -6769,7 +6768,7 @@ public void SupportsIndexingParametersInSubPaths() In = ParameterLocation.Path, Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -7210,16 +7209,16 @@ public void AddReservedPathParameterSymbol() { var userSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, { "displayName", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -7241,7 +7240,7 @@ public void AddReservedPathParameterSymbol() In = ParameterLocation.Path, Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String }, Extensions = { ["x-ms-reserved-parameter"] = new OpenApiReservedParameterExtension { @@ -7292,16 +7291,16 @@ public void DoesNotAddReservedPathParameterSymbol() { var userSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "id", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }, { "displayName", new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } } }, @@ -7323,7 +7322,7 @@ public void DoesNotAddReservedPathParameterSymbol() In = ParameterLocation.Path, Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String }, Extensions = { ["x-ms-reserved-parameter"] = new OpenApiReservedParameterExtension { @@ -7718,7 +7717,8 @@ public async Task CleanupSymbolNameDoesNotCauseNameConflictsInQueryParametersAsy - name: select in: query schema: - type: int64 + type: number + format: int64 responses: '200': content: @@ -7871,7 +7871,7 @@ public async Task SupportsMultiPartFormAsRequestBodyWithoutEncodingWithDefaultMi var bodyParameter = postMethod.Parameters.FirstOrDefault(static x => x.IsOfKind(CodeParameterKind.RequestBody)); Assert.NotNull(bodyParameter); Assert.Equal("MultipartBody", bodyParameter.Type.Name, StringComparer.OrdinalIgnoreCase); - var addressClass = codeModel.FindChildByName("Address"); + var addressClass = codeModel.FindChildByName("Address"); // json is structured, we generated a model Assert.NotNull(addressClass); } [Fact] @@ -7929,9 +7929,8 @@ public async Task SupportsMultiPartFormAsRequestBodyWithoutEncodingWithDefaultMi Assert.NotNull(postMethod); var bodyParameter = postMethod.Parameters.FirstOrDefault(static x => x.IsOfKind(CodeParameterKind.RequestBody)); Assert.NotNull(bodyParameter); - Assert.Equal("DirectoryObjectPostRequestBody", bodyParameter.Type.Name, StringComparer.OrdinalIgnoreCase); //generate the model type as we do not have the serializer for the schema registered. - var addressClass = codeModel.FindChildByName("Address"); - Assert.NotNull(addressClass); + Assert.Equal("MultipartBody", bodyParameter.Type.Name, StringComparer.OrdinalIgnoreCase); + Assert.Null(codeModel.FindChildByName("Address")); // json is not structured so we didn't generate a model for the address } [Fact] public async Task SupportsMultipleContentTypesAsRequestBodyWithDefaultMimeTypesAsync() @@ -9441,11 +9440,11 @@ public void SupportsIncludeFilterAndExcludeWithOperation() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -9586,11 +9585,11 @@ public void SupportsIncludeFilterAndExcludeWithOperationForSpecificPath() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -9731,11 +9730,11 @@ public void CleansUpOperationIdAddsMissingOperationId() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, @@ -9833,11 +9832,11 @@ public void CleansUpOperationIdChangesOperationId() { var myObjectSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Properties = new Dictionary { { "name", new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, } } }, diff --git a/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiAiReasoningInstructionsExtensionTests.cs b/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiAiReasoningInstructionsExtensionTests.cs index 5b34465903..cd7492744f 100644 --- a/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiAiReasoningInstructionsExtensionTests.cs +++ b/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiAiReasoningInstructionsExtensionTests.cs @@ -1,12 +1,13 @@ using System; using System.IO; using System.Net.Http; +using System.Text; +using System.Text.Json.Nodes; using System.Threading.Tasks; using Kiota.Builder.Configuration; using Kiota.Builder.OpenApiExtensions; using Microsoft.Extensions.Logging; using Microsoft.OpenApi; -using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Writers; using Moq; using Xunit; @@ -22,10 +23,15 @@ public void Dispose() [Fact] public void Parses() { - var oaiValue = new OpenApiArray { - new OpenApiString("This is a description"), - new OpenApiString("This is a description 2"), - }; + var oaiValueRepresentation = + """ + [ + "This is a description", + "This is a description 2" + ] + """; + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(oaiValueRepresentation)); + var oaiValue = JsonNode.Parse(stream); var value = OpenApiAiReasoningInstructionsExtension.Parse(oaiValue); Assert.NotNull(value); Assert.Equal("This is a description", value.ReasoningInstructions[0]); diff --git a/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiAiRespondingInstructionsExtensionTests.cs b/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiAiRespondingInstructionsExtensionTests.cs index d14f85a70e..e900673fbc 100644 --- a/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiAiRespondingInstructionsExtensionTests.cs +++ b/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiAiRespondingInstructionsExtensionTests.cs @@ -1,12 +1,13 @@ using System; using System.IO; using System.Net.Http; +using System.Text; +using System.Text.Json.Nodes; using System.Threading.Tasks; using Kiota.Builder.Configuration; using Kiota.Builder.OpenApiExtensions; using Microsoft.Extensions.Logging; using Microsoft.OpenApi; -using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Writers; using Moq; using Xunit; @@ -22,10 +23,15 @@ public void Dispose() [Fact] public void Parses() { - var oaiValue = new OpenApiArray { - new OpenApiString("This is a description"), - new OpenApiString("This is a description 2"), - }; + var oaiValueRepresentation = + """ + [ + "This is a description", + "This is a description 2" + ] + """; + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(oaiValueRepresentation)); + var oaiValue = JsonNode.Parse(stream); var value = OpenApiAiRespondingInstructionsExtension.Parse(oaiValue); Assert.NotNull(value); Assert.Equal("This is a description", value.RespondingInstructions[0]); diff --git a/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiDescriptionForModelExtensionTests.cs b/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiDescriptionForModelExtensionTests.cs index bfcec098c2..c81192394a 100644 --- a/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiDescriptionForModelExtensionTests.cs +++ b/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiDescriptionForModelExtensionTests.cs @@ -6,7 +6,6 @@ using Kiota.Builder.OpenApiExtensions; using Microsoft.Extensions.Logging; using Microsoft.OpenApi; -using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Writers; using Moq; using Xunit; @@ -22,8 +21,7 @@ public void Dispose() [Fact] public void Parses() { - var oaiValue = new OpenApiString("This is a description"); - var value = OpenApiDescriptionForModelExtension.Parse(oaiValue); + var value = OpenApiDescriptionForModelExtension.Parse("This is a description"); Assert.NotNull(value); Assert.Equal("This is a description", value.Description); } diff --git a/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiKiotaExtensionTests.cs b/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiKiotaExtensionTests.cs index 872f0ca6db..50d598a883 100644 --- a/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiKiotaExtensionTests.cs +++ b/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiKiotaExtensionTests.cs @@ -1,7 +1,8 @@ using System.IO; +using System.Text; +using System.Text.Json.Nodes; using Kiota.Builder.OpenApiExtensions; using Microsoft.OpenApi; -using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Writers; using Xunit; @@ -49,30 +50,33 @@ public void Serializes() [Fact] public void Parses() { - var oaiValue = new OpenApiObject + var oaiValueRepresentation = + """ { - { "languagesInformation", new OpenApiObject { - {"CSharp", new OpenApiObject { - {"dependencies", new OpenApiArray { - new OpenApiObject { - {"name", new OpenApiString("Microsoft.Graph.Core")}, - {"version", new OpenApiString("1.0.0") }, - {"type", new OpenApiString("bundle")} - } - }}, - {"dependencyInstallCommand", new OpenApiString("dotnet add package") }, - {"maturityLevel", new OpenApiString("Preview")}, - {"supportExperience", new OpenApiString("Microsoft")}, - {"clientClassName", new OpenApiString("GraphServiceClient")}, - {"clientNamespaceName", new OpenApiString("Microsoft.Graph")}, - {"structuredMimeTypes", new OpenApiArray { - new OpenApiString("application/json"), - new OpenApiString("application/xml")} - }, - } + "languagesInformation": { + "CSharp": { + "dependencies": [ + { + "name": "Microsoft.Graph.Core", + "version": "1.0.0", + "type": "bundle" + } + ], + "dependencyInstallCommand": "dotnet add package", + "maturityLevel": "Preview", + "supportExperience": "Microsoft", + "clientClassName": "GraphServiceClient", + "clientNamespaceName": "Microsoft.Graph", + "structuredMimeTypes": [ + "application/json", + "application/xml" + ] } - }} - }; + } + } + """; + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(oaiValueRepresentation)); + var oaiValue = JsonNode.Parse(stream); var value = OpenApiKiotaExtension.Parse(oaiValue); Assert.NotNull(value); Assert.True(value.LanguagesInformation.TryGetValue("CSharp", out var CSEntry)); diff --git a/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs b/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs index 6743f5c63a..15d39158c0 100644 --- a/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs +++ b/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs @@ -9,7 +9,7 @@ using Kiota.Builder.Plugins; using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Readers; +using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Services; using Microsoft.Plugins.Manifest; using Moq; @@ -75,13 +75,12 @@ public async Task GeneratesManifestAsync(string inputPluginName, string expected var workingDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); var simpleDescriptionPath = Path.Combine(workingDirectory) + "description.yaml"; await File.WriteAllTextAsync(simpleDescriptionPath, simpleDescriptionContent); - var mockLogger = new Mock>(); var openAPIDocumentDS = new OpenApiDocumentDownloadService(_httpClient, _logger); var outputDirectory = Path.Combine(workingDirectory, "output"); var generationConfiguration = new GenerationConfiguration { OutputPath = outputDirectory, - OpenAPIFilePath = "openapiPath", + OpenAPIFilePath = simpleDescriptionPath, PluginTypes = [PluginType.APIPlugin, PluginType.APIManifest, PluginType.OpenAI], ClientClassName = inputPluginName, ApiRootUrl = "http://localhost/", //Kiota builder would set this for us @@ -234,7 +233,7 @@ public async Task GeneratesManifestAndCleansUpInputDescriptionAsync() var generationConfiguration = new GenerationConfiguration { OutputPath = outputDirectory, - OpenAPIFilePath = "openapiPath", + OpenAPIFilePath = simpleDescriptionPath, PluginTypes = [PluginType.APIPlugin], ClientClassName = "client", ApiRootUrl = "http://localhost/", //Kiota builder would set this for us @@ -260,12 +259,11 @@ public async Task GeneratesManifestAndCleansUpInputDescriptionAsync() Assert.Equal(2, resultingManifest.Document.Capabilities.ConversationStarters.Count);// conversation starters are generated for each function Assert.Empty(resultingManifest.Problems);// no problems are expected with names - var openApiReader = new OpenApiStreamReader(); - // Validate the original file. - var originalOpenApiFile = File.OpenRead(simpleDescriptionPath); - var originalDocument = openApiReader.Read(originalOpenApiFile, out var originalDiagnostic); - Assert.Empty(originalDiagnostic.Errors); + using var originalOpenApiFile = File.OpenRead(simpleDescriptionPath); + var originalResult = await OpenApiDocument.LoadAsync(originalOpenApiFile, "yaml"); + var originalDocument = originalResult.Document; + Assert.Empty(originalResult.Diagnostic.Errors); Assert.Equal(originalDocument.Paths["/test"].Operations[OperationType.Get].Description, resultingManifest.Document.Functions[0].Description);// pulls from description Assert.Equal(originalDocument.Paths["/test/{id}"].Operations[OperationType.Get].Summary, resultingManifest.Document.Functions[1].Description);// pulls from summary @@ -280,12 +278,13 @@ public async Task GeneratesManifestAndCleansUpInputDescriptionAsync() Assert.Equal(2, originalDocument.Paths["/test/{id}"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema.AllOf[0].Properties["id"].AnyOf.Count); // anyOf we selected // Validate the output open api file - var resultOpenApiFile = File.OpenRead(Path.Combine(outputDirectory, OpenApiFileName)); - var resultDocument = openApiReader.Read(resultOpenApiFile, out var diagnostic); - Assert.Empty(diagnostic.Errors); + using var resultOpenApiFile = File.OpenRead(Path.Combine(outputDirectory, OpenApiFileName)); + var resultResult = await OpenApiDocument.LoadAsync(originalOpenApiFile, "yaml"); + var resultDocument = resultResult.Document; + Assert.Empty(resultResult.Diagnostic.Errors); // Assertions / validations - Assert.Single(resultDocument.Components.Schemas);// no schema is referenced. so ensure they are all removed + Assert.Empty(resultDocument.Components.Schemas);// no schema is referenced. so ensure they are all removed Assert.Empty(resultDocument.Extensions); // no extension at root (unsupported extension is removed) Assert.Equal(2, resultDocument.Paths.Count); // document has only two paths Assert.Equal(originalDocument.Paths["/test"].Operations[OperationType.Get].Responses.Count - 1, resultDocument.Paths["/test"].Operations[OperationType.Get].Responses.Count); // We removed the error response @@ -297,7 +296,7 @@ public async Task GeneratesManifestAndCleansUpInputDescriptionAsync() Assert.Single(resultDocument.Paths["/test/{id}"].Operations[OperationType.Get].Extensions); // 1 supported extension still present in operation Assert.Empty(resultDocument.Paths["/test/{id}"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema.AllOf); // allOf were merged Assert.Empty(resultDocument.Paths["/test/{id}"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema.Properties["id"].AnyOf); // anyOf we selected - Assert.Equal("string", resultDocument.Paths["/test/{id}"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema.Properties["id"].Type); + Assert.Equal(JsonSchemaType.String, resultDocument.Paths["/test/{id}"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema.Properties["id"].Type.Value); Assert.DoesNotContain("500", resultDocument.Paths["/test/{id}"].Operations[OperationType.Get].Responses.Keys, StringComparer.OrdinalIgnoreCase); // We removed the error response } @@ -487,13 +486,12 @@ public async Task GeneratesManifestWithAuthAsync(string securitySchemesComponent var workingDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); var simpleDescriptionPath = Path.Combine(workingDirectory) + "description.yaml"; await File.WriteAllTextAsync(simpleDescriptionPath, apiDescription); - var mockLogger = new Mock>(); var openApiDocumentDs = new OpenApiDocumentDownloadService(_httpClient, _logger); var outputDirectory = Path.Combine(workingDirectory, "output"); var generationConfiguration = new GenerationConfiguration { OutputPath = outputDirectory, - OpenAPIFilePath = "openapiPath", + OpenAPIFilePath = simpleDescriptionPath, PluginTypes = [PluginType.APIPlugin], ClientClassName = "client", ApiRootUrl = "http://localhost/", //Kiota builder would set this for us @@ -566,13 +564,12 @@ public async Task GeneratesManifestWithMultipleSecuritySchemesAsync() var workingDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); var simpleDescriptionPath = Path.Combine(workingDirectory) + "description.yaml"; await File.WriteAllTextAsync(simpleDescriptionPath, apiDescription); - var mockLogger = new Mock>(); var openApiDocumentDs = new OpenApiDocumentDownloadService(_httpClient, _logger); var outputDirectory = Path.Combine(workingDirectory, "output"); var generationConfiguration = new GenerationConfiguration { OutputPath = outputDirectory, - OpenAPIFilePath = "openapiPath", + OpenAPIFilePath = simpleDescriptionPath, PluginTypes = [PluginType.APIPlugin], ClientClassName = "client", ApiRootUrl = "http://localhost/", //Kiota builder would set this for us @@ -645,7 +642,7 @@ public static TheoryData> Assert.NotEmpty(slicedDocument.Paths); var schema = slicedDocument.Paths["/test"].Operations[OperationType.Post].RequestBody .Content["application/json"].Schema; - Assert.Equal("string", schema.Type); + Assert.Equal(JsonSchemaType.String, schema.Type.Value); Assert.Equal(5, schema.MaxLength); } }, @@ -665,7 +662,7 @@ public static TheoryData> Assert.NotEmpty(slicedDocument.Paths); var schema = slicedDocument.Paths["/test"].Operations[OperationType.Post].RequestBody .Content["application/json"].Schema; - Assert.Equal("object", schema.Type); + Assert.Equal(JsonSchemaType.Object, schema.Type.Value); Assert.Equal(3, schema.Properties.Count); } }, @@ -685,7 +682,7 @@ public static TheoryData> Assert.NotEmpty(slicedDocument.Paths); var schema = slicedDocument.Paths["/test"].Operations[OperationType.Post].RequestBody .Content["application/json"].Schema; - Assert.Equal("object", schema.Type); + Assert.Equal(JsonSchemaType.Object, schema.Type.Value); Assert.Equal(2, schema.Properties.Count); } }, @@ -705,7 +702,7 @@ public static TheoryData> Assert.NotEmpty(slicedDocument.Paths); var schema = slicedDocument.Paths["/test"].Operations[OperationType.Post].RequestBody .Content["application/json"].Schema; - Assert.Equal("object", schema.Type); + Assert.Equal(JsonSchemaType.Object, schema.Type.Value); Assert.Equal(2, schema.Properties.Count); } }, @@ -725,7 +722,7 @@ public static TheoryData> Assert.NotEmpty(slicedDocument.Paths); var schema = slicedDocument.Paths["/test"].Operations[OperationType.Post].RequestBody .Content["application/json"].Schema; - Assert.Equal("object", schema.Type); + Assert.Equal(JsonSchemaType.Object, schema.Type.Value); Assert.Single(schema.Properties); } }, @@ -741,7 +738,7 @@ public static TheoryData> Assert.NotEmpty(slicedDocument.Paths); var schema = slicedDocument.Paths["/test"].Operations[OperationType.Post].RequestBody .Content["application/json"].Schema; - Assert.Equal("object", schema.Type); + Assert.Equal(JsonSchemaType.Object, schema.Type.Value); Assert.Single(schema.Properties); } }, @@ -777,7 +774,7 @@ public async Task MergesAllOfRequestBodyAsync(string content, Action GetDiagnosticFromDocumentAsync(string document) + { + var rule = new DivergentResponseSchema(new()); + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(document)); + var settings = new OpenApiReaderSettings(); + settings.RuleSet.Add(typeof(OpenApiOperation), [rule]); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader()); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yml, new OpenApiYamlReader()); + var result = await OpenApiDocument.LoadAsync(stream, "yaml", settings); + return result.Diagnostic; } } diff --git a/tests/Kiota.Builder.Tests/Validation/GetWithBodyTests.cs b/tests/Kiota.Builder.Tests/Validation/GetWithBodyTests.cs index 99ba847d8c..89ea47f7b1 100644 --- a/tests/Kiota.Builder.Tests/Validation/GetWithBodyTests.cs +++ b/tests/Kiota.Builder.Tests/Validation/GetWithBodyTests.cs @@ -1,6 +1,9 @@ using System.IO; using System.Text; +using System.Threading.Tasks; using Kiota.Builder.Validation; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Readers; using Microsoft.OpenApi.Validations; using Xunit; @@ -10,9 +13,8 @@ namespace Kiota.Builder.Tests.Validation; public class GetWithBodyTests { [Fact] - public void AddsAWarningWhenGetWithBody() + public async Task AddsAWarningWhenGetWithBody() { - var rule = new GetWithBody(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -27,20 +29,15 @@ public void AddsAWarningWhenGetWithBody() application/json: responses: '200': + description: some description content: application/json:"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Single(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Single(diagnostic.Warnings); } [Fact] - public void DoesntAddAWarningWhenGetWithNoBody() + public async Task DoesntAddAWarningWhenGetWithNoBody() { - var rule = new GetWithBody(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -53,20 +50,15 @@ public void DoesntAddAWarningWhenGetWithNoBody() get: responses: '200': + description: some description content: application/json:"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Empty(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Empty(diagnostic.Warnings); } [Fact] - public void DoesntAddAWarningWhenPostWithBody() + public async Task DoesntAddAWarningWhenPostWithBody() { - var rule = new GetWithBody(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -81,14 +73,21 @@ public void DoesntAddAWarningWhenPostWithBody() application/json: responses: '200': + description: some description content: application/json:"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Empty(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Empty(diagnostic.Warnings); + } + private static async Task GetDiagnosticFromDocumentAsync(string document) + { + var rule = new GetWithBody(); + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(document)); + var settings = new OpenApiReaderSettings(); + settings.RuleSet.Add(typeof(OpenApiPathItem), [rule]); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader()); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yml, new OpenApiYamlReader()); + var result = await OpenApiDocument.LoadAsync(stream, "yaml", settings); + return result.Diagnostic; } } diff --git a/tests/Kiota.Builder.Tests/Validation/InconsistentTypeFormatPairTests.cs b/tests/Kiota.Builder.Tests/Validation/InconsistentTypeFormatPairTests.cs index 9b46823c30..4c3d61f8f3 100644 --- a/tests/Kiota.Builder.Tests/Validation/InconsistentTypeFormatPairTests.cs +++ b/tests/Kiota.Builder.Tests/Validation/InconsistentTypeFormatPairTests.cs @@ -1,17 +1,18 @@ using System.IO; using System.Text; +using System.Threading.Tasks; using Kiota.Builder.Validation; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Readers; -using Microsoft.OpenApi.Validations; using Xunit; namespace Kiota.Builder.Tests.Validation; public class InconsistentTypeFormatPairTests { [Fact] - public void AddsAWarningWhenKnownInconsistentPair() + public async Task AddsAWarningWhenKnownInconsistentPair() { - var rule = new InconsistentTypeFormatPair(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -22,23 +23,18 @@ public void AddsAWarningWhenKnownInconsistentPair() get: responses: '200': + description: some description content: application/json: schema: type: string format: int32"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Single(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Single(diagnostic.Warnings); } [Fact] - public void DoesntAddAWarningWhenSupportedPair() + public async Task DoesntAddAWarningWhenSupportedPair() { - var rule = new InconsistentTypeFormatPair(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -49,23 +45,18 @@ public void DoesntAddAWarningWhenSupportedPair() get: responses: '200': + description: some description content: application/json: schema: type: string format: uuid"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Empty(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Empty(diagnostic.Warnings); } [Fact] - public void DoesntFailWhenKnownAlternative() + public async Task DoesntFailWhenKnownAlternative() { - var rule = new InconsistentTypeFormatPair(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -76,17 +67,24 @@ public void DoesntFailWhenKnownAlternative() get: responses: '200': + description: some description content: application/json: schema: type: enum format: string"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Empty(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Empty(diagnostic.Warnings); + } + private static async Task GetDiagnosticFromDocumentAsync(string document) + { + var rule = new InconsistentTypeFormatPair(); + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(document)); + var settings = new OpenApiReaderSettings(); + settings.RuleSet.Add(typeof(OpenApiSchema), [rule]); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader()); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yml, new OpenApiYamlReader()); + var result = await OpenApiDocument.LoadAsync(stream, "yaml", settings); + return result.Diagnostic; } } diff --git a/tests/Kiota.Builder.Tests/Validation/KnownAndNotSupportedFormatsTests.cs b/tests/Kiota.Builder.Tests/Validation/KnownAndNotSupportedFormatsTests.cs index 8df9463cf9..abc24f3ac3 100644 --- a/tests/Kiota.Builder.Tests/Validation/KnownAndNotSupportedFormatsTests.cs +++ b/tests/Kiota.Builder.Tests/Validation/KnownAndNotSupportedFormatsTests.cs @@ -1,8 +1,10 @@ using System.IO; using System.Text; +using System.Threading.Tasks; using Kiota.Builder.Validation; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Readers; -using Microsoft.OpenApi.Validations; using Xunit; namespace Kiota.Builder.Tests.Validation; @@ -10,9 +12,8 @@ namespace Kiota.Builder.Tests.Validation; public class KnownAndNotSupportedFormatsTests { [Fact] - public void AddsAWarningWhenKnownUnsupportedFormat() + public async Task AddsAWarningWhenKnownUnsupportedFormat() { - var rule = new KnownAndNotSupportedFormats(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -23,23 +24,18 @@ public void AddsAWarningWhenKnownUnsupportedFormat() get: responses: '200': + description: some description content: application/json: schema: type: string format: email"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Single(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Single(diagnostic.Warnings); } [Fact] - public void DoesntAddAWarningWhenSupportedFormat() + public async Task DoesntAddAWarningWhenSupportedFormat() { - var rule = new KnownAndNotSupportedFormats(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -50,23 +46,18 @@ public void DoesntAddAWarningWhenSupportedFormat() get: responses: '200': + description: some description content: application/json: schema: type: string format: uuid"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Empty(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Empty(diagnostic.Warnings); } [Fact] - public void DoesntFailWhenNoFormat() + public async Task DoesntFailWhenNoFormat() { - var rule = new KnownAndNotSupportedFormats(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -77,17 +68,23 @@ public void DoesntFailWhenNoFormat() get: responses: '200': + description: some description content: application/json: schema: type: string"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Empty(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Empty(diagnostic.Warnings); + } + private static async Task GetDiagnosticFromDocumentAsync(string document) + { + var rule = new KnownAndNotSupportedFormats(); + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(document)); + var settings = new OpenApiReaderSettings(); + settings.RuleSet.Add(typeof(OpenApiSchema), [rule]); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader()); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yml, new OpenApiYamlReader()); + var result = await OpenApiDocument.LoadAsync(stream, "yaml", settings); + return result.Diagnostic; } - } diff --git a/tests/Kiota.Builder.Tests/Validation/MissingDiscriminatorTests.cs b/tests/Kiota.Builder.Tests/Validation/MissingDiscriminatorTests.cs index d112997287..efd89a1c2b 100644 --- a/tests/Kiota.Builder.Tests/Validation/MissingDiscriminatorTests.cs +++ b/tests/Kiota.Builder.Tests/Validation/MissingDiscriminatorTests.cs @@ -1,17 +1,18 @@ using System.IO; using System.Text; +using System.Threading.Tasks; using Kiota.Builder.Validation; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Readers; -using Microsoft.OpenApi.Validations; using Xunit; namespace Kiota.Builder.Tests.Validation; public class MissingDiscriminatorTests { [Fact] - public void DoesntAddAWarningWhenBodyIsSimple() + public async Task DoesntAddAWarningWhenBodyIsSimple() { - var rule = new MissingDiscriminator(new()); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -22,23 +23,18 @@ public void DoesntAddAWarningWhenBodyIsSimple() get: responses: '200': + description: some description content: application/json: schema: type: string format: int32"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Empty(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Empty(diagnostic.Warnings); } [Fact] - public void AddsWarningOnInlineSchemas() + public async Task AddsWarningOnInlineSchemas() { - var rule = new MissingDiscriminator(new()); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -49,6 +45,7 @@ public void AddsWarningOnInlineSchemas() get: responses: '200': + description: some description content: application/json: schema: @@ -62,18 +59,12 @@ public void AddsWarningOnInlineSchemas() properties: type2: type: string"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Single(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Single(diagnostic.Warnings); } [Fact] - public void AddsWarningOnComponentSchemas() + public async Task AddsWarningOnComponentSchemas() { - var rule = new MissingDiscriminator(new()); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -101,22 +92,17 @@ public void AddsWarningOnComponentSchemas() get: responses: '200': + description: some description content: application/json: schema: $ref: '#/components/schemas/type3'"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Single(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Single(diagnostic.Warnings); } [Fact] - public void DoesntAddsWarningOnComponentSchemasWithDiscriminatorInformation() + public async Task DoesntAddsWarningOnComponentSchemasWithDiscriminatorInformation() { - var rule = new MissingDiscriminator(new()); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -146,22 +132,17 @@ public void DoesntAddsWarningOnComponentSchemasWithDiscriminatorInformation() get: responses: '200': + description: some description content: application/json: schema: $ref: '#/components/schemas/type3'"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Empty(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Empty(diagnostic.Warnings); } [Fact] - public void DoesntAddsWarningOnComponentSchemasScalars() + public async Task DoesntAddsWarningOnComponentSchemasScalars() { - var rule = new MissingDiscriminator(new()); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -181,16 +162,23 @@ public void DoesntAddsWarningOnComponentSchemasScalars() get: responses: '200': + description: some description content: application/json: schema: $ref: '#/components/schemas/type1'"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Empty(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Empty(diagnostic.Warnings); + } + private static async Task GetDiagnosticFromDocumentAsync(string document) + { + var rule = new MissingDiscriminator(new()); + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(document)); + var settings = new OpenApiReaderSettings(); + settings.RuleSet.Add(typeof(OpenApiDocument), [rule]); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader()); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yml, new OpenApiYamlReader()); + var result = await OpenApiDocument.LoadAsync(stream, "yaml", settings); + return result.Diagnostic; } } diff --git a/tests/Kiota.Builder.Tests/Validation/MultipleServerEntriesTests.cs b/tests/Kiota.Builder.Tests/Validation/MultipleServerEntriesTests.cs index 0bbd417140..d6585196e9 100644 --- a/tests/Kiota.Builder.Tests/Validation/MultipleServerEntriesTests.cs +++ b/tests/Kiota.Builder.Tests/Validation/MultipleServerEntriesTests.cs @@ -1,8 +1,10 @@ using System.IO; using System.Text; +using System.Threading.Tasks; using Kiota.Builder.Validation; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Readers; -using Microsoft.OpenApi.Validations; using Xunit; namespace Kiota.Builder.Tests.Validation; @@ -10,9 +12,8 @@ namespace Kiota.Builder.Tests.Validation; public class MultipleServerEntriesTests { [Fact] - public void AddsAWarningWhenMultipleServersPresent() + public async Task AddsAWarningWhenMultipleServersPresent() { - var rule = new MultipleServerEntries(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -26,20 +27,15 @@ public void AddsAWarningWhenMultipleServersPresent() get: responses: '200': + description: some description content: application/json:"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Single(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Single(diagnostic.Warnings); } [Fact] - public void DoesntAddAWarningWhenSingleServerPresent() + public async Task DoesntAddAWarningWhenSingleServerPresent() { - var rule = new MultipleServerEntries(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -52,14 +48,21 @@ public void DoesntAddAWarningWhenSingleServerPresent() get: responses: '200': + description: some description content: application/json:"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Empty(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Empty(diagnostic.Warnings); + } + private static async Task GetDiagnosticFromDocumentAsync(string document) + { + var rule = new MultipleServerEntries(); + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(document)); + var settings = new OpenApiReaderSettings(); + settings.RuleSet.Add(typeof(OpenApiDocument), [rule]); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader()); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yml, new OpenApiYamlReader()); + var result = await OpenApiDocument.LoadAsync(stream, "yaml", settings); + return result.Diagnostic; } } diff --git a/tests/Kiota.Builder.Tests/Validation/NoContentWithBodyTests.cs b/tests/Kiota.Builder.Tests/Validation/NoContentWithBodyTests.cs index d0924580c3..ce59591fff 100644 --- a/tests/Kiota.Builder.Tests/Validation/NoContentWithBodyTests.cs +++ b/tests/Kiota.Builder.Tests/Validation/NoContentWithBodyTests.cs @@ -1,8 +1,10 @@ using System.IO; using System.Text; +using System.Threading.Tasks; using Kiota.Builder.Validation; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Readers; -using Microsoft.OpenApi.Validations; using Xunit; namespace Kiota.Builder.Tests.Validation; @@ -10,9 +12,8 @@ namespace Kiota.Builder.Tests.Validation; public class NoContentWithBodyTests { [Fact] - public void AddsAWarningWhen204WithBody() + public async Task AddsAWarningWhen204WithBody() { - var rule = new NoContentWithBody(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -23,20 +24,15 @@ public void AddsAWarningWhen204WithBody() get: responses: '204': + description: some description content: application/json:"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Single(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Single(diagnostic.Warnings); } [Fact] - public void DoesntAddAWarningWhen204WithNoBody() + public async Task DoesntAddAWarningWhen204WithNoBody() { - var rule = new NoContentWithBody(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -48,19 +44,14 @@ public void DoesntAddAWarningWhen204WithNoBody() /enumeration: get: responses: - '204':"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Empty(diag.Warnings); + '204': + description: some description"; + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Empty(diagnostic.Warnings); } [Fact] - public void DoesntAddAWarningWhen200WithBody() + public async Task DoesntAddAWarningWhen200WithBody() { - var rule = new NoContentWithBody(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -75,15 +66,21 @@ public void DoesntAddAWarningWhen200WithBody() application/json: responses: '200': + description: some description content: application/json:"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Empty(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Empty(diagnostic.Warnings); + } + private static async Task GetDiagnosticFromDocumentAsync(string document) + { + var rule = new NoContentWithBody(); + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(document)); + var settings = new OpenApiReaderSettings(); + settings.RuleSet.Add(typeof(OpenApiOperation), [rule]); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader()); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yml, new OpenApiYamlReader()); + var result = await OpenApiDocument.LoadAsync(stream, "yaml", settings); + return result.Diagnostic; } - } diff --git a/tests/Kiota.Builder.Tests/Validation/NoServerEntryTests.cs b/tests/Kiota.Builder.Tests/Validation/NoServerEntryTests.cs index acae1bf4b3..cc488df6db 100644 --- a/tests/Kiota.Builder.Tests/Validation/NoServerEntryTests.cs +++ b/tests/Kiota.Builder.Tests/Validation/NoServerEntryTests.cs @@ -1,8 +1,10 @@ using System.IO; using System.Text; +using System.Threading.Tasks; using Kiota.Builder.Validation; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Readers; -using Microsoft.OpenApi.Validations; using Xunit; namespace Kiota.Builder.Tests.Validation; @@ -10,9 +12,8 @@ namespace Kiota.Builder.Tests.Validation; public class NoServerEntryTests { [Fact] - public void AddsAWarningWhenNoServersPresent() + public async Task AddsAWarningWhenNoServersPresent() { - var rule = new NoServerEntry(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -25,18 +26,12 @@ public void AddsAWarningWhenNoServersPresent() '200': content: application/json:"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Single(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Single(diagnostic.Warnings); } [Fact] - public void DoesntAddAWarningWhenServerPresent() + public async Task DoesntAddAWarningWhenServerPresent() { - var rule = new NoServerEntry(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -51,12 +46,18 @@ public void DoesntAddAWarningWhenServerPresent() '200': content: application/json:"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Empty(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Empty(diagnostic.Warnings); + } + private static async Task GetDiagnosticFromDocumentAsync(string document) + { + var rule = new NoServerEntry(); + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(document)); + var settings = new OpenApiReaderSettings(); + settings.RuleSet.Add(typeof(OpenApiDocument), [rule]); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader()); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yml, new OpenApiYamlReader()); + var result = await OpenApiDocument.LoadAsync(stream, "yaml", settings); + return result.Diagnostic; } } diff --git a/tests/Kiota.Builder.Tests/Validation/UrlFormEncodedComplexTests.cs b/tests/Kiota.Builder.Tests/Validation/UrlFormEncodedComplexTests.cs index a45f0f9498..3482735a3e 100644 --- a/tests/Kiota.Builder.Tests/Validation/UrlFormEncodedComplexTests.cs +++ b/tests/Kiota.Builder.Tests/Validation/UrlFormEncodedComplexTests.cs @@ -1,17 +1,18 @@ using System.IO; using System.Text; +using System.Threading.Tasks; using Kiota.Builder.Validation; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Readers; -using Microsoft.OpenApi.Validations; using Xunit; namespace Kiota.Builder.Tests.Validation; public class UrlFormEncodedComplexTests { [Fact] - public void AddsAWarningWhenUrlEncodedNotObjectRequestBody() + public async Task AddsAWarningWhenUrlEncodedNotObjectRequestBody() { - var rule = new UrlFormEncodedComplex(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -28,23 +29,18 @@ public void AddsAWarningWhenUrlEncodedNotObjectRequestBody() format: int32 responses: '200': + description: some description content: application/json: schema: type: string format: int32"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Single(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Single(diagnostic.Warnings); } [Fact] - public void AddsAWarningWhenUrlEncodedNotObjectResponse() + public async Task AddsAWarningWhenUrlEncodedNotObjectResponse() { - var rule = new UrlFormEncodedComplex(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -55,23 +51,18 @@ public void AddsAWarningWhenUrlEncodedNotObjectResponse() get: responses: '200': + description: some description content: application/x-www-form-urlencoded: schema: type: string format: int32"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Single(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Single(diagnostic.Warnings); } [Fact] - public void AddsAWarningWhenUrlEncodedComplexPropertyOnRequestBody() + public async Task AddsAWarningWhenUrlEncodedComplexPropertyOnRequestBody() { - var rule = new UrlFormEncodedComplex(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -93,23 +84,18 @@ public void AddsAWarningWhenUrlEncodedComplexPropertyOnRequestBody() type: string responses: '200': + description: some description content: application/json: schema: type: string format: int32"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Single(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Single(diagnostic.Warnings); } [Fact] - public void AddsAWarningWhenUrlEncodedComplexPropertyOnResponse() + public async Task AddsAWarningWhenUrlEncodedComplexPropertyOnResponse() { - var rule = new UrlFormEncodedComplex(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -120,6 +106,7 @@ public void AddsAWarningWhenUrlEncodedComplexPropertyOnResponse() get: responses: '200': + description: some description content: application/x-www-form-urlencoded: schema: @@ -130,18 +117,12 @@ public void AddsAWarningWhenUrlEncodedComplexPropertyOnResponse() properties: prop: type: string"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Single(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Single(diagnostic.Warnings); } [Fact] - public void DoesntAddAWarningWhenUrlEncoded() + public async Task DoesntAddAWarningWhenUrlEncoded() { - var rule = new UrlFormEncodedComplex(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -152,6 +133,7 @@ public void DoesntAddAWarningWhenUrlEncoded() get: responses: '200': + description: some description content: application/x-www-form-urlencoded: schema: @@ -159,18 +141,12 @@ public void DoesntAddAWarningWhenUrlEncoded() properties: prop: type: string"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Empty(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Empty(diagnostic.Warnings); } [Fact] - public void DoesntAddAWarningOnArrayProperty() + public async Task DoesntAddAWarningOnArrayProperty() { - var rule = new UrlFormEncodedComplex(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -192,6 +168,7 @@ public void DoesntAddAWarningOnArrayProperty() format: int32 responses: '200': + description: some description content: application/x-www-form-urlencoded: schema: @@ -199,18 +176,12 @@ public void DoesntAddAWarningOnArrayProperty() properties: prop: type: string"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Empty(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Empty(diagnostic.Warnings); } [Fact] - public void DoesntAddAWarningWhenNotUrlEncoded() + public async Task DoesntAddAWarningWhenNotUrlEncoded() { - var rule = new UrlFormEncodedComplex(); var documentTxt = @"openapi: 3.0.1 info: title: OData Service for namespace microsoft.graph @@ -221,17 +192,24 @@ public void DoesntAddAWarningWhenNotUrlEncoded() get: responses: '200': + description: some description content: application/json: schema: type: enum format: string"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(documentTxt)); - var reader = new OpenApiStreamReader(new OpenApiReaderSettings - { - RuleSet = new(new ValidationRule[] { rule }), - }); - var doc = reader.Read(stream, out var diag); - Assert.Empty(diag.Warnings); + var diagnostic = await GetDiagnosticFromDocumentAsync(documentTxt); + Assert.Empty(diagnostic.Warnings); + } + private static async Task GetDiagnosticFromDocumentAsync(string document) + { + var rule = new UrlFormEncodedComplex(); + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(document)); + var settings = new OpenApiReaderSettings(); + settings.RuleSet.Add(typeof(OpenApiOperation), [rule]); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader()); + OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yml, new OpenApiYamlReader()); + var result = await OpenApiDocument.LoadAsync(stream, "yaml", settings); + return result.Diagnostic; } } diff --git a/tests/Kiota.Builder.Tests/Validation/ValidationRuleSetExtensionsTests.cs b/tests/Kiota.Builder.Tests/Validation/ValidationRuleSetExtensionsTests.cs index 7159d17db0..1bba9f1448 100644 --- a/tests/Kiota.Builder.Tests/Validation/ValidationRuleSetExtensionsTests.cs +++ b/tests/Kiota.Builder.Tests/Validation/ValidationRuleSetExtensionsTests.cs @@ -19,7 +19,7 @@ public void DisablesAllRules() var ruleSet = new ValidationRuleSet(); var configuration = new GenerationConfiguration { DisabledValidationRules = new() { "all" } }; ruleSet.AddKiotaValidationRules(configuration); - Assert.Empty(ruleSet); + Assert.Empty(ruleSet.Rules); } [Fact] public void DisablesNoRule() @@ -27,15 +27,15 @@ public void DisablesNoRule() var ruleSet = new ValidationRuleSet(); var configuration = new GenerationConfiguration { DisabledValidationRules = new() }; ruleSet.AddKiotaValidationRules(configuration); - Assert.NotEmpty(ruleSet); + Assert.NotEmpty(ruleSet.Rules); } [Fact] public void DisablesOneRule() { var ruleSet = new ValidationRuleSet(); - var configuration = new GenerationConfiguration { DisabledValidationRules = new() { nameof(NoServerEntry) } }; + var configuration = new GenerationConfiguration { DisabledValidationRules = [nameof(NoServerEntry)] }; ruleSet.AddKiotaValidationRules(configuration); - Assert.NotEmpty(ruleSet); - Assert.DoesNotContain(ruleSet, static x => x.GetType() == typeof(NoServerEntry)); + Assert.NotEmpty(ruleSet.Rules); + Assert.DoesNotContain(ruleSet.Rules, static x => x.GetType() == typeof(NoServerEntry)); } }