diff --git a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs index fbfb1b716..8749e4537 100644 --- a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs +++ b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs @@ -52,7 +52,8 @@ public override void Visit(OpenApiSchema schema) public override void Visit(OpenApiPathItem pathItem) { - if (pathItem.Operations.TryGetValue(OperationType.Put, out var value)) + if (pathItem.Operations.TryGetValue(OperationType.Put, out var value) && + value.OperationId != null) { var operationId = value.OperationId; pathItem.Operations[OperationType.Put].OperationId = ResolvePutOperationId(operationId); @@ -67,14 +68,14 @@ public override void Visit(OpenApiOperation operation) throw new ArgumentException($"OperationId is required {PathString}", nameof(operation)); var operationId = operation.OperationId; - var operationTypeExtension = operation.Extensions.GetExtension("x-ms-docs-operation-type"); + var operationTypeExtension = operation.Extensions?.GetExtension("x-ms-docs-operation-type"); if (operationTypeExtension.IsEquals("function")) - operation.Parameters = ResolveFunctionParameters(operation.Parameters); + operation.Parameters = ResolveFunctionParameters(operation.Parameters ?? new List()); // Order matters. Resolve operationId. operationId = RemoveHashSuffix(operationId); if (operationTypeExtension.IsEquals("action") || operationTypeExtension.IsEquals("function")) - operationId = RemoveKeyTypeSegment(operationId, operation.Parameters); + operationId = RemoveKeyTypeSegment(operationId, operation.Parameters ?? new List()); operationId = SingularizeAndDeduplicateOperationId(operationId.SplitByChar('.')); operationId = ResolveODataCastOperationId(operationId); operationId = ResolveByRefOperationId(operationId); diff --git a/src/Microsoft.OpenApi.Hidi/OpenApiService.cs b/src/Microsoft.OpenApi.Hidi/OpenApiService.cs index fd53086d2..df3bf0e67 100644 --- a/src/Microsoft.OpenApi.Hidi/OpenApiService.cs +++ b/src/Microsoft.OpenApi.Hidi/OpenApiService.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs index 5079e9915..f672b7dd1 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs @@ -8,6 +8,7 @@ using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; +#nullable enable namespace Microsoft.OpenApi.Models { @@ -19,60 +20,60 @@ public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible /// /// An object to hold reusable Objects. /// - public IDictionary Schemas { get; set; } = new Dictionary(); + public IDictionary? Schemas { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public virtual IDictionary Responses { get; set; } = new Dictionary(); + public virtual IDictionary? Responses { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public virtual IDictionary Parameters { get; set; } = + public virtual IDictionary? Parameters { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public virtual IDictionary Examples { get; set; } = new Dictionary(); + public virtual IDictionary? Examples { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public virtual IDictionary RequestBodies { get; set; } = + public virtual IDictionary? RequestBodies { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public virtual IDictionary Headers { get; set; } = new Dictionary(); + public virtual IDictionary? Headers { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public virtual IDictionary SecuritySchemes { get; set; } = + public virtual IDictionary? SecuritySchemes { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public virtual IDictionary Links { get; set; } = new Dictionary(); + public virtual IDictionary? Links { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public virtual IDictionary Callbacks { get; set; } = new Dictionary(); + public virtual IDictionary? Callbacks { get; set; } = new Dictionary(); /// /// An object to hold reusable Object. /// - public virtual IDictionary PathItems { get; set; } = new Dictionary(); + public virtual IDictionary? PathItems { get; set; } = new Dictionary(); /// /// This object MAY be extended with Specification Extensions. /// - public virtual IDictionary Extensions { get; set; } = new Dictionary(); + public virtual IDictionary? Extensions { get; set; } = new Dictionary(); /// /// Parameter-less constructor @@ -82,7 +83,7 @@ public OpenApiComponents() { } /// /// Initializes a copy of an object /// - public OpenApiComponents(OpenApiComponents components) + public OpenApiComponents(OpenApiComponents? components) { Schemas = components?.Schemas != null ? new Dictionary(components.Schemas) : null; Responses = components?.Responses != null ? new Dictionary(components.Responses) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 5fee30ac2..8b80fe958 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -16,6 +16,8 @@ using Microsoft.OpenApi.Services; using Microsoft.OpenApi.Writers; +#nullable enable + namespace Microsoft.OpenApi.Models { /// @@ -26,7 +28,7 @@ public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible /// /// Related workspace containing OpenApiDocuments that are referenced in this document /// - public OpenApiWorkspace Workspace { get; set; } + public OpenApiWorkspace? Workspace { get; set; } /// /// REQUIRED. Provides metadata about the API. The metadata MAY be used by tooling as required. @@ -36,12 +38,12 @@ public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible /// /// The default value for the $schema keyword within Schema Objects contained within this OAS document. This MUST be in the form of a URI. /// - public string JsonSchemaDialect { get; set; } + public string? JsonSchemaDialect { get; set; } /// /// An array of Server Objects, which provide connectivity information to a target server. /// - public IList Servers { get; set; } = new List(); + public IList? Servers { get; set; } = new List(); /// /// REQUIRED. The available paths and operations for the API. @@ -53,33 +55,33 @@ public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible /// A map of requests initiated other than by an API call, for example by an out of band registration. /// The key name is a unique string to refer to each webhook, while the (optionally referenced) Path Item Object describes a request that may be initiated by the API provider and the expected responses /// - public IDictionary Webhooks { get; set; } = new Dictionary(); + public IDictionary? Webhooks { get; set; } = new Dictionary(); /// /// An element to hold various schemas for the specification. /// - public OpenApiComponents Components { get; set; } + public OpenApiComponents? Components { get; set; } /// /// A declaration of which security mechanisms can be used across the API. /// - public IList SecurityRequirements { get; set; } = + public IList? SecurityRequirements { get; set; } = new List(); /// /// A list of tags used by the specification with additional metadata. /// - public IList Tags { get; set; } = new List(); + public IList? Tags { get; set; } = new List(); /// /// Additional external documentation. /// - public OpenApiExternalDocs ExternalDocs { get; set; } + public OpenApiExternalDocs? ExternalDocs { get; set; } /// /// This object MAY be extended with Specification Extensions. /// - public IDictionary Extensions { get; set; } = new Dictionary(); + public IDictionary? Extensions { get; set; } = new Dictionary(); /// /// The unique hash code of the generated OpenAPI document @@ -97,25 +99,28 @@ public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible public OpenApiDocument() { Workspace = new OpenApiWorkspace(); - BaseUri = new(OpenApiConstants.BaseRegistryUri + Guid.NewGuid().ToString()); + BaseUri = new(OpenApiConstants.BaseRegistryUri + Guid.NewGuid()); + Info = new OpenApiInfo(); + Paths = new OpenApiPaths(); } /// /// Initializes a copy of an an object /// - public OpenApiDocument(OpenApiDocument document) + public OpenApiDocument(OpenApiDocument? document) { Workspace = document?.Workspace != null ? new(document?.Workspace) : null; - Info = document?.Info != null ? new(document?.Info) : null; + Info = document?.Info != null ? new(document?.Info) : new OpenApiInfo(); JsonSchemaDialect = document?.JsonSchemaDialect ?? JsonSchemaDialect; Servers = document?.Servers != null ? new List(document.Servers) : null; - Paths = document?.Paths != null ? new(document?.Paths) : null; + Paths = document?.Paths != null ? new(document?.Paths) : new OpenApiPaths(); Webhooks = document?.Webhooks != null ? new Dictionary(document.Webhooks) : null; Components = document?.Components != null ? new(document?.Components) : null; SecurityRequirements = document?.SecurityRequirements != null ? new List(document.SecurityRequirements) : null; Tags = document?.Tags != null ? new List(document.Tags) : null; ExternalDocs = document?.ExternalDocs != null ? new(document?.ExternalDocs) : null; Extensions = document?.Extensions != null ? new Dictionary(document.Extensions) : null; + BaseUri = document?.BaseUri != null ? document.BaseUri : new(OpenApiConstants.BaseRegistryUri + Guid.NewGuid()); } /// @@ -360,7 +365,7 @@ private static string ParseServerUrl(OpenApiServer server) return parsedUrl; } - private static void WriteHostInfoV2(IOpenApiWriter writer, IList servers) + private static void WriteHostInfoV2(IOpenApiWriter writer, IList? servers) { if (servers == null || !servers.Any()) { @@ -440,7 +445,7 @@ public void SetReferenceHostDocument() /// /// Load the referenced object from a object /// - internal T ResolveReferenceTo(OpenApiReference reference) where T : class, IOpenApiReferenceable + internal T? ResolveReferenceTo(OpenApiReference reference) where T : class, IOpenApiReferenceable { if (reference.IsExternal) { @@ -489,7 +494,7 @@ private static string ConvertByteArrayToString(byte[] hash) /// /// Load the referenced object from a object /// - internal IOpenApiReferenceable ResolveReference(OpenApiReference reference, bool useExternal) + internal IOpenApiReferenceable? ResolveReference(OpenApiReference? reference, bool useExternal) { if (reference == null) { @@ -504,7 +509,7 @@ internal IOpenApiReferenceable ResolveReference(OpenApiReference reference, bool // Special case for Tag if (reference.Type == ReferenceType.Tag) { - foreach (var tag in this.Tags) + foreach (var tag in this.Tags ?? Enumerable.Empty()) { if (tag.Name == reference.Id) { @@ -526,11 +531,11 @@ internal IOpenApiReferenceable ResolveReference(OpenApiReference reference, bool string relativePath = OpenApiConstants.ComponentsSegment + reference.Type.GetDisplayName() + "/" + reference.Id; uriLocation = useExternal - ? Workspace.GetDocumentId(reference.ExternalResource)?.OriginalString + relativePath + ? Workspace?.GetDocumentId(reference.ExternalResource)?.OriginalString + relativePath : BaseUri + relativePath; } - return Workspace.ResolveReference(uriLocation); + return Workspace?.ResolveReference(uriLocation); } /// @@ -539,7 +544,7 @@ internal IOpenApiReferenceable ResolveReference(OpenApiReference reference, bool /// The path to the OpenAPI file. /// /// - public static ReadResult Load(string url, OpenApiReaderSettings settings = null) + public static ReadResult Load(string url, OpenApiReaderSettings? settings = null) { return OpenApiModelFactory.Load(url, settings); } @@ -553,7 +558,7 @@ public static ReadResult Load(string url, OpenApiReaderSettings settings = null) /// public static ReadResult Load(Stream stream, string format, - OpenApiReaderSettings settings = null) + OpenApiReaderSettings? settings = null) { return OpenApiModelFactory.Load(stream, format, settings); } @@ -567,7 +572,7 @@ public static ReadResult Load(Stream stream, /// public static ReadResult Load(TextReader input, string format, - OpenApiReaderSettings settings = null) + OpenApiReaderSettings? settings = null) { return OpenApiModelFactory.Load(input, format, settings); } @@ -578,7 +583,7 @@ public static ReadResult Load(TextReader input, /// The path to the OpenAPI file. /// The OpenApi reader settings. /// - public static async Task LoadAsync(string url, OpenApiReaderSettings settings = null) + public static async Task LoadAsync(string url, OpenApiReaderSettings? settings = null) { return await OpenApiModelFactory.LoadAsync(url, settings); } @@ -591,7 +596,7 @@ public static async Task LoadAsync(string url, OpenApiReaderSettings /// The OpenApi reader settings. /// Propagates information about operation cancelling. /// - public static async Task LoadAsync(Stream stream, string format, OpenApiReaderSettings settings = null, CancellationToken cancellationToken = default) + public static async Task LoadAsync(Stream stream, string format, OpenApiReaderSettings? settings = null, CancellationToken cancellationToken = default) { return await OpenApiModelFactory.LoadAsync(stream, format, settings, cancellationToken); } @@ -603,7 +608,7 @@ public static async Task LoadAsync(Stream stream, string format, Ope /// The OpenAPI format to use during parsing. /// The OpenApi reader settings. /// - public static async Task LoadAsync(TextReader input, string format, OpenApiReaderSettings settings = null) + public static async Task LoadAsync(TextReader input, string format, OpenApiReaderSettings? settings = null) { return await OpenApiModelFactory.LoadAsync(input, format, settings); } @@ -616,8 +621,8 @@ public static async Task LoadAsync(TextReader input, string format, /// /// public static ReadResult Parse(string input, - string format = null, - OpenApiReaderSettings settings = null) + string? format = null, + OpenApiReaderSettings? settings = null) { return OpenApiModelFactory.Parse(input, format, settings); } @@ -625,9 +630,9 @@ public static ReadResult Parse(string input, internal class FindSchemaReferences : OpenApiVisitorBase { - private Dictionary Schemas; + private Dictionary Schemas = new(); - public static void ResolveSchemas(OpenApiComponents components, Dictionary schemas) + public static void ResolveSchemas(OpenApiComponents? components, Dictionary schemas) { var visitor = new FindSchemaReferences(); visitor.Schemas = schemas; diff --git a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs index 7183d5808..17af31e64 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs @@ -8,6 +8,8 @@ using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; +#nullable enable + namespace Microsoft.OpenApi.Models { /// @@ -15,12 +17,12 @@ namespace Microsoft.OpenApi.Models /// public class OpenApiMediaType : IOpenApiSerializable, IOpenApiExtensible { - private OpenApiSchema _schema; + private OpenApiSchema? _schema; /// /// The schema defining the type used for the request body. /// - public virtual OpenApiSchema Schema + public virtual OpenApiSchema? Schema { get => _schema; set => _schema = value; @@ -30,13 +32,13 @@ public virtual OpenApiSchema Schema /// Example of the media type. /// The example object SHOULD be in the correct format as specified by the media type. /// - public JsonNode Example { get; set; } + public JsonNode? Example { get; set; } /// /// Examples of the media type. /// Each example object SHOULD match the media type and specified schema if present. /// - public IDictionary Examples { get; set; } = new Dictionary(); + public IDictionary? Examples { get; set; } = new Dictionary(); /// /// A map between a property name and its encoding information. @@ -44,12 +46,12 @@ public virtual OpenApiSchema Schema /// The encoding object SHALL only apply to requestBody objects /// when the media type is multipart or application/x-www-form-urlencoded. /// - public IDictionary Encoding { get; set; } = new Dictionary(); + public IDictionary? Encoding { get; set; } = new Dictionary(); /// /// Serialize to Open Api v3.0. /// - public IDictionary Extensions { get; set; } = new Dictionary(); + public IDictionary? Extensions { get; set; } = new Dictionary(); /// /// Parameterless constructor @@ -59,7 +61,7 @@ public OpenApiMediaType() { } /// /// Initializes a copy of an object /// - public OpenApiMediaType(OpenApiMediaType mediaType) + public OpenApiMediaType(OpenApiMediaType? mediaType) { _schema = mediaType?.Schema != null ? new(mediaType.Schema) : null; Example = mediaType?.Example != null ? JsonNodeCloneHelper.Clone(mediaType.Example) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs index 498e93306..4da68d082 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs @@ -8,6 +8,8 @@ using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; +#nullable enable + namespace Microsoft.OpenApi.Models { /// @@ -24,30 +26,30 @@ public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible /// A list of tags for API documentation control. /// Tags can be used for logical grouping of operations by resources or any other qualifier. /// - public IList Tags { get; set; } = new List(); + public IList? Tags { get; set; } = new List(); /// /// A short summary of what the operation does. /// - public string Summary { get; set; } + public string? Summary { get; set; } /// /// A verbose explanation of the operation behavior. /// CommonMark syntax MAY be used for rich text representation. /// - public string Description { get; set; } + public string? Description { get; set; } /// /// Additional external documentation for this operation. /// - public OpenApiExternalDocs ExternalDocs { get; set; } + public OpenApiExternalDocs? ExternalDocs { get; set; } /// /// Unique string used to identify the operation. The id MUST be unique among all operations described in the API. /// Tools and libraries MAY use the operationId to uniquely identify an operation, therefore, /// it is RECOMMENDED to follow common programming naming conventions. /// - public string OperationId { get; set; } + public string? OperationId { get; set; } /// /// A list of parameters that are applicable for this operation. @@ -55,7 +57,7 @@ public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible /// The list MUST NOT include duplicated parameters. A unique parameter is defined by a combination of a name and location. /// The list can use the Reference Object to link to parameters that are defined at the OpenAPI Object's components/parameters. /// - public IList Parameters { get; set; } = new List(); + public IList? Parameters { get; set; } = new List(); /// /// The request body applicable for this operation. @@ -63,12 +65,12 @@ public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible /// has explicitly defined semantics for request bodies. /// In other cases where the HTTP spec is vague, requestBody SHALL be ignored by consumers. /// - public OpenApiRequestBody RequestBody { get; set; } + public OpenApiRequestBody? RequestBody { get; set; } /// /// REQUIRED. The list of possible responses as they are returned from executing this operation. /// - public OpenApiResponses Responses { get; set; } = new(); + public OpenApiResponses? Responses { get; set; } = new(); /// /// A map of possible out-of band callbacks related to the parent operation. @@ -78,7 +80,7 @@ public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible /// The key value used to identify the callback object is an expression, evaluated at runtime, /// that identifies a URL to use for the callback operation. /// - public IDictionary Callbacks { get; set; } = new Dictionary(); + public IDictionary? Callbacks { get; set; } = new Dictionary(); /// /// Declares this operation to be deprecated. Consumers SHOULD refrain from usage of the declared operation. @@ -92,19 +94,19 @@ public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible /// This definition overrides any declared top-level security. /// To remove a top-level security declaration, an empty array can be used. /// - public IList Security { get; set; } = new List(); + public IList? Security { get; set; } = new List(); /// /// An alternative server array to service this operation. /// If an alternative server object is specified at the Path Item Object or Root level, /// it will be overridden by this value. /// - public IList Servers { get; set; } = new List(); + public IList? Servers { get; set; } = new List(); /// /// This object MAY be extended with Specification Extensions. /// - public IDictionary Extensions { get; set; } = new Dictionary(); + public IDictionary? Extensions { get; set; } = new Dictionary(); /// /// Parameterless constructor @@ -114,9 +116,9 @@ public OpenApiOperation() { } /// /// Initializes a copy of an object /// - public OpenApiOperation(OpenApiOperation operation) + public OpenApiOperation(OpenApiOperation? operation) { - Tags = operation?.Tags != null ? new List(operation?.Tags) : null; + Tags = operation?.Tags != null ? new List(operation.Tags) : null; Summary = operation?.Summary ?? Summary; Description = operation?.Description ?? Description; ExternalDocs = operation?.ExternalDocs != null ? new(operation?.ExternalDocs) : null; diff --git a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs index 9cf54f65a..2dd882ce7 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs @@ -105,11 +105,11 @@ internal void Walk(OpenApiExternalDocs externalDocs) _visitor.Visit(externalDocs); } - +#nullable enable /// /// Visits and child objects /// - internal void Walk(OpenApiComponents components) + internal void Walk(OpenApiComponents? components) { if (components == null) { @@ -118,11 +118,6 @@ internal void Walk(OpenApiComponents components) _visitor.Visit(components); - if (components == null) - { - return; - } - Walk(OpenApiConstants.Schemas, () => { if (components.Schemas != null) @@ -236,6 +231,7 @@ internal void Walk(OpenApiComponents components) Walk(components as IOpenApiExtensible); } +#nullable restore /// /// Visits and child objects /// diff --git a/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs b/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs index 319a5d63f..a51ccd9c3 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs @@ -121,13 +121,14 @@ public bool Contains(string location) return _IOpenApiReferenceableRegistry.ContainsKey(key) || _artifactsRegistry.ContainsKey(key); } +#nullable enable /// /// Resolves a reference given a key. /// /// /// /// The resolved reference. - public T ResolveReference(string location) + public T? ResolveReference(string location) { if (string.IsNullOrEmpty(location)) return default; @@ -143,6 +144,7 @@ public T ResolveReference(string location) return default; } +#nullable restore private Uri ToLocationUrl(string location) { diff --git a/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs b/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs index bbf00fef0..f6102f316 100644 --- a/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs +++ b/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs @@ -125,6 +125,7 @@ public static void WriteProperty(this IOpenApiWriter writer, string name, T v writer.WriteValue(value); } +#nullable enable /// /// Write the optional Open API object/element. /// @@ -136,7 +137,7 @@ public static void WriteProperty(this IOpenApiWriter writer, string name, T v public static void WriteOptionalObject( this IOpenApiWriter writer, string name, - T value, + T? value, Action action) { if (value != null) @@ -161,7 +162,7 @@ public static void WriteOptionalObject( public static void WriteRequiredObject( this IOpenApiWriter writer, string name, - T value, + T? value, Action action) { Utils.CheckArgumentNull(action); @@ -177,6 +178,7 @@ public static void WriteRequiredObject( writer.WriteEndObject(); } } +#nullable restore /// /// Write the optional of collection string. diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs index 94f99a1d2..214bd47ff 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs @@ -57,18 +57,21 @@ public void RemoveAnyOfAndOneOfFromSchema() var walker = new OpenApiWalker(powerShellFormatter); walker.Walk(openApiDocument); - var testSchema = openApiDocument.Components.Schemas["TestSchema"]; - var averageAudioDegradationProperty = testSchema.Properties["averageAudioDegradation"]; - var defaultPriceProperty = testSchema.Properties["defaultPrice"]; + var testSchema = openApiDocument.Components?.Schemas?["TestSchema"]; + var averageAudioDegradationProperty = testSchema?.Properties["averageAudioDegradation"]; + var defaultPriceProperty = testSchema?.Properties["defaultPrice"]; // Assert - Assert.Null(averageAudioDegradationProperty.AnyOf); - Assert.Equal("number", averageAudioDegradationProperty.Type); - Assert.Equal("float", averageAudioDegradationProperty.Format); - Assert.True(averageAudioDegradationProperty.Nullable); - Assert.Null(defaultPriceProperty.OneOf); - Assert.Equal("number", defaultPriceProperty.Type); - Assert.Equal("double", defaultPriceProperty.Format); + Assert.NotNull(openApiDocument.Components); + Assert.NotNull(openApiDocument.Components.Schemas); + Assert.NotNull(testSchema); + Assert.Null(averageAudioDegradationProperty?.AnyOf); + Assert.Equal("number", averageAudioDegradationProperty?.Type); + Assert.Equal("float", averageAudioDegradationProperty?.Format); + Assert.True(averageAudioDegradationProperty?.Nullable); + Assert.Null(defaultPriceProperty?.OneOf); + Assert.Equal("number", defaultPriceProperty?.Type); + Assert.Equal("double", defaultPriceProperty?.Format); Assert.NotNull(testSchema.AdditionalProperties); } @@ -83,7 +86,7 @@ public void ResolveFunctionParameters() var walker = new OpenApiWalker(powerShellFormatter); walker.Walk(openApiDocument); - var idsParameter = openApiDocument.Paths["/foo"].Operations[OperationType.Get].Parameters.Where(static p => p.Name == "ids").FirstOrDefault(); + var idsParameter = openApiDocument.Paths["/foo"].Operations[OperationType.Get].Parameters?.Where(static p => p.Name == "ids").FirstOrDefault(); // Assert Assert.Null(idsParameter?.Content); diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 7eb01a70c..33c61f484 100755 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -336,18 +336,18 @@ namespace Microsoft.OpenApi.Models public class OpenApiComponents : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiComponents() { } - public OpenApiComponents(Microsoft.OpenApi.Models.OpenApiComponents components) { } - public System.Collections.Generic.IDictionary Schemas { get; set; } - public virtual System.Collections.Generic.IDictionary Callbacks { get; set; } - public virtual System.Collections.Generic.IDictionary Examples { get; set; } - public virtual System.Collections.Generic.IDictionary Extensions { get; set; } - public virtual System.Collections.Generic.IDictionary Headers { get; set; } - public virtual System.Collections.Generic.IDictionary Links { get; set; } - public virtual System.Collections.Generic.IDictionary Parameters { get; set; } - public virtual System.Collections.Generic.IDictionary PathItems { get; set; } - public virtual System.Collections.Generic.IDictionary RequestBodies { get; set; } - public virtual System.Collections.Generic.IDictionary Responses { get; set; } - public virtual System.Collections.Generic.IDictionary SecuritySchemes { get; set; } + public OpenApiComponents(Microsoft.OpenApi.Models.OpenApiComponents? components) { } + public System.Collections.Generic.IDictionary? Schemas { get; set; } + public virtual System.Collections.Generic.IDictionary? Callbacks { get; set; } + public virtual System.Collections.Generic.IDictionary? Examples { get; set; } + public virtual System.Collections.Generic.IDictionary? Extensions { get; set; } + public virtual System.Collections.Generic.IDictionary? Headers { get; set; } + public virtual System.Collections.Generic.IDictionary? Links { get; set; } + public virtual System.Collections.Generic.IDictionary? Parameters { get; set; } + public virtual System.Collections.Generic.IDictionary? PathItems { get; set; } + public virtual System.Collections.Generic.IDictionary? RequestBodies { get; set; } + public virtual System.Collections.Generic.IDictionary? Responses { get; set; } + public virtual System.Collections.Generic.IDictionary? SecuritySchemes { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -531,32 +531,32 @@ namespace Microsoft.OpenApi.Models public class OpenApiDocument : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiDocument() { } - public OpenApiDocument(Microsoft.OpenApi.Models.OpenApiDocument document) { } + public OpenApiDocument(Microsoft.OpenApi.Models.OpenApiDocument? document) { } public System.Uri BaseUri { get; } - public Microsoft.OpenApi.Models.OpenApiComponents Components { get; set; } - public System.Collections.Generic.IDictionary Extensions { get; set; } - public Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } + public Microsoft.OpenApi.Models.OpenApiComponents? Components { get; set; } + public System.Collections.Generic.IDictionary? Extensions { get; set; } + public Microsoft.OpenApi.Models.OpenApiExternalDocs? ExternalDocs { get; set; } public string HashCode { get; } public Microsoft.OpenApi.Models.OpenApiInfo Info { get; set; } - public string JsonSchemaDialect { get; set; } + public string? JsonSchemaDialect { get; set; } public Microsoft.OpenApi.Models.OpenApiPaths Paths { get; set; } - public System.Collections.Generic.IList SecurityRequirements { get; set; } - public System.Collections.Generic.IList Servers { get; set; } - public System.Collections.Generic.IList Tags { get; set; } - public System.Collections.Generic.IDictionary Webhooks { get; set; } - public Microsoft.OpenApi.Services.OpenApiWorkspace Workspace { get; set; } + public System.Collections.Generic.IList? SecurityRequirements { get; set; } + public System.Collections.Generic.IList? Servers { get; set; } + public System.Collections.Generic.IList? Tags { get; set; } + public System.Collections.Generic.IDictionary? Webhooks { get; set; } + public Microsoft.OpenApi.Services.OpenApiWorkspace? Workspace { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SetReferenceHostDocument() { } public static string GenerateHashValue(Microsoft.OpenApi.Models.OpenApiDocument doc) { } - public static Microsoft.OpenApi.Reader.ReadResult Load(string url, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) { } - public static Microsoft.OpenApi.Reader.ReadResult Load(System.IO.Stream stream, string format, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) { } - public static Microsoft.OpenApi.Reader.ReadResult Load(System.IO.TextReader input, string format, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) { } - public static System.Threading.Tasks.Task LoadAsync(string url, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) { } - public static System.Threading.Tasks.Task LoadAsync(System.IO.TextReader input, string format, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) { } - public static System.Threading.Tasks.Task LoadAsync(System.IO.Stream stream, string format, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null, System.Threading.CancellationToken cancellationToken = default) { } - public static Microsoft.OpenApi.Reader.ReadResult Parse(string input, string format = null, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) { } + public static Microsoft.OpenApi.Reader.ReadResult Load(string url, Microsoft.OpenApi.Reader.OpenApiReaderSettings? settings = null) { } + public static Microsoft.OpenApi.Reader.ReadResult Load(System.IO.Stream stream, string format, Microsoft.OpenApi.Reader.OpenApiReaderSettings? settings = null) { } + public static Microsoft.OpenApi.Reader.ReadResult Load(System.IO.TextReader input, string format, Microsoft.OpenApi.Reader.OpenApiReaderSettings? settings = null) { } + public static System.Threading.Tasks.Task LoadAsync(string url, Microsoft.OpenApi.Reader.OpenApiReaderSettings? settings = null) { } + public static System.Threading.Tasks.Task LoadAsync(System.IO.TextReader input, string format, Microsoft.OpenApi.Reader.OpenApiReaderSettings? settings = null) { } + public static System.Threading.Tasks.Task LoadAsync(System.IO.Stream stream, string format, Microsoft.OpenApi.Reader.OpenApiReaderSettings? settings = null, System.Threading.CancellationToken cancellationToken = default) { } + public static Microsoft.OpenApi.Reader.ReadResult Parse(string input, string? format = null, Microsoft.OpenApi.Reader.OpenApiReaderSettings? settings = null) { } } public class OpenApiEncoding : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -688,12 +688,12 @@ namespace Microsoft.OpenApi.Models public class OpenApiMediaType : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiMediaType() { } - public OpenApiMediaType(Microsoft.OpenApi.Models.OpenApiMediaType mediaType) { } - public System.Collections.Generic.IDictionary Encoding { get; set; } - public System.Text.Json.Nodes.JsonNode Example { get; set; } - public System.Collections.Generic.IDictionary Examples { get; set; } - public System.Collections.Generic.IDictionary Extensions { get; set; } - public virtual Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } + public OpenApiMediaType(Microsoft.OpenApi.Models.OpenApiMediaType? mediaType) { } + public System.Collections.Generic.IDictionary? Encoding { get; set; } + public System.Text.Json.Nodes.JsonNode? Example { get; set; } + public System.Collections.Generic.IDictionary? Examples { get; set; } + public System.Collections.Generic.IDictionary? Extensions { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiSchema? Schema { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -728,20 +728,20 @@ namespace Microsoft.OpenApi.Models { public const bool DeprecatedDefault = false; public OpenApiOperation() { } - public OpenApiOperation(Microsoft.OpenApi.Models.OpenApiOperation operation) { } - public System.Collections.Generic.IDictionary Callbacks { get; set; } + public OpenApiOperation(Microsoft.OpenApi.Models.OpenApiOperation? operation) { } + public System.Collections.Generic.IDictionary? Callbacks { get; set; } public bool Deprecated { get; set; } - public string Description { get; set; } - public System.Collections.Generic.IDictionary Extensions { get; set; } - public Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } - public string OperationId { get; set; } - public System.Collections.Generic.IList Parameters { get; set; } - public Microsoft.OpenApi.Models.OpenApiRequestBody RequestBody { get; set; } - public Microsoft.OpenApi.Models.OpenApiResponses Responses { get; set; } - public System.Collections.Generic.IList Security { get; set; } - public System.Collections.Generic.IList Servers { get; set; } - public string Summary { get; set; } - public System.Collections.Generic.IList Tags { get; set; } + public string? Description { get; set; } + public System.Collections.Generic.IDictionary? Extensions { get; set; } + public Microsoft.OpenApi.Models.OpenApiExternalDocs? ExternalDocs { get; set; } + public string? OperationId { get; set; } + public System.Collections.Generic.IList? Parameters { get; set; } + public Microsoft.OpenApi.Models.OpenApiRequestBody? RequestBody { get; set; } + public Microsoft.OpenApi.Models.OpenApiResponses? Responses { get; set; } + public System.Collections.Generic.IList? Security { get; set; } + public System.Collections.Generic.IList? Servers { get; set; } + public string? Summary { get; set; } + public System.Collections.Generic.IList? Tags { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1512,7 +1512,7 @@ namespace Microsoft.OpenApi.Services public bool Contains(string location) { } public System.Uri GetDocumentId(string key) { } public bool RegisterComponent(string location, T component) { } - public T ResolveReference(string location) { } + public T? ResolveReference(string location) { } } public class OperationSearch : Microsoft.OpenApi.Services.OpenApiVisitorBase { @@ -1837,7 +1837,7 @@ namespace Microsoft.OpenApi.Writers where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { } public static void WriteOptionalMap(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IDictionary elements, System.Action action) where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { } - public static void WriteOptionalObject(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, T value, System.Action action) { } + public static void WriteOptionalObject(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, T? value, System.Action action) { } public static void WriteProperty(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, string value) { } public static void WriteProperty(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, bool value, bool defaultValue = false) { } public static void WriteProperty(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, bool? value, bool defaultValue = false) { } @@ -1850,7 +1850,7 @@ namespace Microsoft.OpenApi.Writers public static void WriteRequiredMap(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IDictionary elements, System.Action action) { } public static void WriteRequiredMap(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IDictionary elements, System.Action action) where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { } - public static void WriteRequiredObject(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, T value, System.Action action) { } + public static void WriteRequiredObject(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, T? value, System.Action action) { } public static void WriteRequiredProperty(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, string value) { } } public class OpenApiWriterSettings diff --git a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs index 924364ccd..698d3fc5c 100644 --- a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs @@ -24,7 +24,9 @@ public void LocateTopLevelObjects() walker.Walk(doc); locator.Locations.Should().BeEquivalentTo(new List { + "#/info", "#/servers", + "#/paths", "#/tags" }); } @@ -39,7 +41,6 @@ public void LocateTopLevelArrayItems() new(), new() }, - Paths = new(), Tags = new List { new() @@ -51,6 +52,7 @@ public void LocateTopLevelArrayItems() walker.Walk(doc); locator.Locations.Should().BeEquivalentTo(new List { + "#/info", "#/servers", "#/servers/0", "#/servers/1", @@ -63,10 +65,7 @@ public void LocateTopLevelArrayItems() [Fact] public void LocatePathOperationContentSchema() { - var doc = new OpenApiDocument - { - Paths = new() - }; + var doc = new OpenApiDocument(); doc.Paths.Add("/test", new() { Operations = new Dictionary @@ -98,6 +97,7 @@ public void LocatePathOperationContentSchema() walker.Walk(doc); locator.Locations.Should().BeEquivalentTo(new List { + "#/info", "#/servers", "#/paths", "#/paths/~1test", @@ -131,7 +131,6 @@ public void WalkDOMWithCycles() var doc = new OpenApiDocument { - Paths = new(), Components = new() { Schemas = new Dictionary @@ -146,6 +145,7 @@ public void WalkDOMWithCycles() walker.Walk(doc); locator.Locations.Should().BeEquivalentTo(new List { + "#/info", "#/servers", "#/paths", "#/components",