Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: enable null reference type support #2146

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ internal static class OpenApiExtensibleExtensions
/// <returns>A <see cref="string"/> value matching the provided extensionKey. Return null when extensionKey is not found. </returns>
internal static string GetExtension(this IDictionary<string, IOpenApiExtension> extensions, string extensionKey)
{
if (extensions.TryGetValue(extensionKey, out var value) && value is OpenApiAny castValue)
if (extensions.TryGetValue(extensionKey, out var value) && value is OpenApiAny castValue && castValue.Node is not null)
{
return castValue.Node.GetValue<string>();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public override void Visit(IOpenApiSchema schema)

public override void Visit(IOpenApiPathItem pathItem)
{
if (pathItem.Operations.TryGetValue(OperationType.Put, out var value) &&
if (pathItem.Operations is not null && pathItem.Operations.TryGetValue(OperationType.Put, out var value) &&
value.OperationId != null)
{
var operationId = value.OperationId;
Expand Down Expand Up @@ -149,7 +149,7 @@ private static string RemoveKeyTypeSegment(string operationId, IList<IOpenApiPar
var segments = operationId.SplitByChar('.');
foreach (var parameter in parameters)
{
var keyTypeExtension = parameter.Extensions.GetExtension("x-ms-docs-key-type");
var keyTypeExtension = parameter.Extensions?.GetExtension("x-ms-docs-key-type");
if (keyTypeExtension != null && operationId.Contains(keyTypeExtension, StringComparison.OrdinalIgnoreCase))
{
segments.Remove(keyTypeExtension);
Expand Down Expand Up @@ -178,7 +178,10 @@ private static void ResolveFunctionParameters(IList<IOpenApiParameter> parameter

private void AddAdditionalPropertiesToSchema(IOpenApiSchema schema)
{
if (schema is OpenApiSchema openApiSchema && !_schemaLoop.Contains(schema) && schema.Type.Equals(JsonSchemaType.Object))
if (schema is OpenApiSchema openApiSchema
&& !_schemaLoop.Contains(schema)
&& schema.Type.Equals(JsonSchemaType.Object)
&& schema.AdditionalProperties is not null)
{
openApiSchema.AdditionalProperties = new OpenApiSchema() { Type = JsonSchemaType.Object };

Expand Down
36 changes: 20 additions & 16 deletions src/Microsoft.OpenApi.Hidi/OpenApiService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ public static async Task TransformOpenApiDocumentAsync(HidiOptions options, ILog
return apiDependency;
}

private static OpenApiDocument ApplyFilters(HidiOptions options, ILogger logger, ApiDependency? apiDependency, JsonDocument? postmanCollection, OpenApiDocument document)
private static OpenApiDocument? ApplyFilters(HidiOptions options, ILogger logger, ApiDependency? apiDependency, JsonDocument? postmanCollection, OpenApiDocument? document)
{
Dictionary<string, List<string>> requestUrls;
if (apiDependency != null)
Expand Down Expand Up @@ -191,7 +191,7 @@ private static OpenApiDocument ApplyFilters(HidiOptions options, ILogger logger,
return document;
}

private static async Task WriteOpenApiAsync(HidiOptions options, OpenApiFormat openApiFormat, OpenApiSpecVersion openApiVersion, OpenApiDocument document, ILogger logger, CancellationToken cancellationToken)
private static async Task WriteOpenApiAsync(HidiOptions options, OpenApiFormat openApiFormat, OpenApiSpecVersion openApiVersion, OpenApiDocument? document, ILogger logger, CancellationToken cancellationToken)
{
using (logger.BeginScope("Output"))
{
Expand Down Expand Up @@ -225,9 +225,9 @@ private static async Task WriteOpenApiAsync(HidiOptions options, OpenApiFormat o
}

// Get OpenAPI document either from OpenAPI or CSDL
private static async Task<OpenApiDocument> GetOpenApiAsync(HidiOptions options, string format, ILogger logger, string? metadataVersion = null, CancellationToken cancellationToken = default)
private static async Task<OpenApiDocument?> GetOpenApiAsync(HidiOptions options, string format, ILogger logger, string? metadataVersion = null, CancellationToken cancellationToken = default)
{
OpenApiDocument document;
OpenApiDocument? document;
Stream stream;

if (!string.IsNullOrEmpty(options.Csdl))
Expand All @@ -248,7 +248,7 @@ private static async Task<OpenApiDocument> GetOpenApiAsync(HidiOptions options,

document = await ConvertCsdlToOpenApiAsync(filteredStream ?? stream, format, metadataVersion, options.SettingsConfig, cancellationToken).ConfigureAwait(false);
stopwatch.Stop();
logger.LogTrace("{Timestamp}ms: Generated OpenAPI with {Paths} paths.", stopwatch.ElapsedMilliseconds, document.Paths.Count);
logger.LogTrace("{Timestamp}ms: Generated OpenAPI with {Paths} paths.", stopwatch.ElapsedMilliseconds, document?.Paths.Count);
}
}
else if (!string.IsNullOrEmpty(options.OpenApi))
Expand All @@ -262,7 +262,7 @@ private static async Task<OpenApiDocument> GetOpenApiAsync(HidiOptions options,
return document;
}

private static Func<string, OperationType?, OpenApiOperation, bool>? FilterOpenApiDocument(string? filterByOperationIds, string? filterByTags, Dictionary<string, List<string>> requestUrls, OpenApiDocument document, ILogger logger)
private static Func<string, OperationType?, OpenApiOperation, bool>? FilterOpenApiDocument(string? filterByOperationIds, string? filterByTags, Dictionary<string, List<string>> requestUrls, OpenApiDocument? document, ILogger logger)
{
Func<string, OperationType?, OpenApiOperation, bool>? predicate = null;

Expand Down Expand Up @@ -376,7 +376,7 @@ private static MemoryStream ApplyFilterToCsdl(Stream csdlStream, string entitySe

if (result is null) return null;

return result.Diagnostic.Errors.Count == 0;
return result.Diagnostic?.Errors.Count == 0;
}

private static async Task<ReadResult> ParseOpenApiAsync(string openApiFile, bool inlineExternal, ILogger logger, Stream stream, CancellationToken cancellationToken = default)
Expand Down Expand Up @@ -411,7 +411,7 @@ private static async Task<ReadResult> ParseOpenApiAsync(string openApiFile, bool
/// </summary>
/// <param name="csdl">The CSDL stream.</param>
/// <returns>An OpenAPI document.</returns>
public static async Task<OpenApiDocument> ConvertCsdlToOpenApiAsync(Stream csdl, string format, string? metadataVersion = null, IConfiguration? settings = null, CancellationToken token = default)
public static async Task<OpenApiDocument?> ConvertCsdlToOpenApiAsync(Stream csdl, string format, string? metadataVersion = null, IConfiguration? settings = null, CancellationToken token = default)
{
using var reader = new StreamReader(csdl);
var csdlText = await reader.ReadToEndAsync(token).ConfigureAwait(false);
Expand All @@ -429,7 +429,7 @@ public static async Task<OpenApiDocument> ConvertCsdlToOpenApiAsync(Stream csdl,
/// </summary>
/// <param name="document"> The converted OpenApiDocument.</param>
/// <returns> A valid OpenApiDocument instance.</returns>
public static OpenApiDocument FixReferences(OpenApiDocument document, string format)
public static OpenApiDocument? FixReferences(OpenApiDocument document, string format)
{
// This method is only needed because the output of ConvertToOpenApi isn't quite a valid OpenApiDocument instance.
// So we write it out, and read it back in again to fix it up.
Expand Down Expand Up @@ -648,7 +648,7 @@ private static string GetInputPathExtension(string? openapi = null, string? csdl
private static void LogErrors(ILogger logger, ReadResult result)
{
var context = result.Diagnostic;
if (context.Errors.Count != 0)
if (context is not null && context.Errors.Count != 0)
{
using (logger.BeginScope("Detected errors"))
{
Expand All @@ -660,11 +660,11 @@ private static void LogErrors(ILogger logger, ReadResult result)
}
}

internal static void WriteTreeDocumentAsMarkdown(string openapiUrl, OpenApiDocument document, StreamWriter writer)
internal static void WriteTreeDocumentAsMarkdown(string openapiUrl, OpenApiDocument? document, StreamWriter writer)
{
var rootNode = OpenApiUrlTreeNode.Create(document, "main");

writer.WriteLine("# " + document.Info.Title);
writer.WriteLine("# " + document?.Info.Title);
writer.WriteLine();
writer.WriteLine("API Description: " + openapiUrl);

Expand All @@ -681,7 +681,7 @@ internal static void WriteTreeDocumentAsMarkdown(string openapiUrl, OpenApiDocum
writer.WriteLine("```");
}

internal static void WriteTreeDocumentAsHtml(string sourceUrl, OpenApiDocument document, StreamWriter writer, bool asHtmlFile = false)
internal static void WriteTreeDocumentAsHtml(string sourceUrl, OpenApiDocument? document, StreamWriter writer, bool asHtmlFile = false)
{
var rootNode = OpenApiUrlTreeNode.Create(document, "main");

Expand All @@ -700,7 +700,7 @@ internal static void WriteTreeDocumentAsHtml(string sourceUrl, OpenApiDocument d
</style>
<body>
""");
writer.WriteLine("<h1>" + document.Info.Title + "</h1>");
writer.WriteLine("<h1>" + document?.Info.Title + "</h1>");
writer.WriteLine();
writer.WriteLine($"<h3> API Description: <a href='{sourceUrl}'>{sourceUrl}</a></h3>");

Expand Down Expand Up @@ -771,9 +771,13 @@ internal static async Task PluginManifestAsync(HidiOptions options, ILogger logg
await WriteOpenApiAsync(options, OpenApiFormat.Json, OpenApiSpecVersion.OpenApi3_1, document, logger, cancellationToken).ConfigureAwait(false);

// Create OpenAIPluginManifest from ApiDependency and OpenAPI document
var manifest = new OpenAIPluginManifest(document.Info?.Title ?? "Title", document.Info?.Title ?? "Title", "https://go.microsoft.com/fwlink/?LinkID=288890", document.Info?.Contact?.Email ?? "[email protected]", document.Info?.License?.Url.ToString() ?? "https://placeholderlicenseurl.com")
var manifest = new OpenAIPluginManifest(document?.Info.Title ?? "Title",
document?.Info.Title ?? "Title",
"https://go.microsoft.com/fwlink/?LinkID=288890",
document?.Info?.Contact?.Email ?? "[email protected]",
document?.Info?.License?.Url?.ToString() ?? "https://placeholderlicenseurl.com")
{
DescriptionForHuman = document.Info?.Description ?? "Description placeholder",
DescriptionForHuman = document?.Info.Description ?? "Description placeholder",
Api = new("openapi", "./openapi.json"),
Auth = new ManifestNoAuth(),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<!-- https://github.com/dotnet/sourcelink/blob/main/docs/README.md#embeduntrackedsources -->
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<NoWarn>NU5048</NoWarn>
<Nullable>enable</Nullable>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>

Expand Down
6 changes: 3 additions & 3 deletions src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,11 @@ public static ReadResult Read(JsonNode jsonNode, OpenApiReaderSettings settings)
}

/// <inheritdoc/>
public T ReadFragment<T>(MemoryStream input,
public T? ReadFragment<T>(MemoryStream input,
OpenApiSpecVersion version,
OpenApiDocument openApiDocument,
out OpenApiDiagnostic diagnostic,
OpenApiReaderSettings settings = null) where T : IOpenApiElement
OpenApiReaderSettings? settings = null) where T : IOpenApiElement
{
if (input is null) throw new ArgumentNullException(nameof(input));
JsonNode jsonNode;
Expand All @@ -110,7 +110,7 @@ public T ReadFragment<T>(MemoryStream input,
}

/// <inheritdoc/>
public static T ReadFragment<T>(JsonNode input, OpenApiSpecVersion version, OpenApiDocument openApiDocument, out OpenApiDiagnostic diagnostic, OpenApiReaderSettings settings = null) where T : IOpenApiElement
public static T ReadFragment<T>(JsonNode input, OpenApiSpecVersion version, OpenApiDocument openApiDocument, out OpenApiDiagnostic diagnostic, OpenApiReaderSettings? settings = null) where T : IOpenApiElement
{
return _jsonReader.ReadFragment<T>(input, version, openApiDocument, out diagnostic, settings);
}
Expand Down
6 changes: 3 additions & 3 deletions src/Microsoft.OpenApi/Any/OpenApiAny.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,21 @@ namespace Microsoft.OpenApi.Any
/// </summary>
public class OpenApiAny : IOpenApiElement, IOpenApiExtension
{
private readonly JsonNode jsonNode;
private readonly JsonNode? jsonNode;

/// <summary>
/// Initializes the <see cref="OpenApiAny"/> class.
/// </summary>
/// <param name="jsonNode"></param>
public OpenApiAny(JsonNode jsonNode)
public OpenApiAny(JsonNode? jsonNode)
{
this.jsonNode = jsonNode;
}

/// <summary>
/// Gets the underlying JsonNode.
/// </summary>
public JsonNode Node { get { return jsonNode; } }
public JsonNode? Node { get { return jsonNode; } }

/// <summary>
/// Writes out the OpenApiAny type.
Expand Down
4 changes: 2 additions & 2 deletions src/Microsoft.OpenApi/Attributes/DisplayAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ public class DisplayAttribute : Attribute
/// Initializes a new instance of the <see cref="DisplayAttribute"/> class.
/// </summary>
/// <param name="name">The display name.</param>
public DisplayAttribute(string name)
public DisplayAttribute(string? name)
{
Name = Utils.CheckArgumentNullOrEmpty(name);
}

/// <summary>
/// The display Name.
/// </summary>
public string Name { get; }
public string? Name { get; }
}
}
4 changes: 2 additions & 2 deletions src/Microsoft.OpenApi/Exceptions/OpenApiException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public OpenApiException(string message)
/// </summary>
/// <param name="message">The plain text error message for this exception.</param>
/// <param name="innerException">The inner exception that is the cause of this exception to be thrown.</param>
public OpenApiException(string message, Exception innerException)
public OpenApiException(string message, Exception? innerException)
: base(message, innerException)
{
}
Expand All @@ -46,6 +46,6 @@ public OpenApiException(string message, Exception innerException)
/// a text/plain pointer as defined in https://tools.ietf.org/html/rfc5147
/// Currently only line= is provided because using char= causes tests to break due to CR/LF and LF differences
/// </summary>
public string Pointer { get; set; }
public string? Pointer { get; set; }
}
}
4 changes: 2 additions & 2 deletions src/Microsoft.OpenApi/Exceptions/OpenApiReaderException.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -11,7 +11,7 @@
/// Defines an exception indicating OpenAPI Reader encountered an issue while reading.
/// </summary>
[Serializable]
public class OpenApiReaderException : OpenApiException

Check warning on line 14 in src/Microsoft.OpenApi/Exceptions/OpenApiReaderException.cs

View workflow job for this annotation

GitHub Actions / Build

Update this implementation of 'ISerializable' to conform to the recommended serialization pattern. Add a 'protected' constructor 'OpenApiReaderException(SerializationInfo, StreamingContext)'. (https://rules.sonarsource.com/csharp/RSPEC-3925)
{
/// <summary>
/// Initializes the <see cref="OpenApiReaderException"/> class.
Expand Down Expand Up @@ -39,7 +39,7 @@
/// </summary>
/// <param name="message">Plain text error message for this exception.</param>
/// <param name="node">Parsing node where error occured</param>
public OpenApiReaderException(string message, JsonNode node) : base(message)
public OpenApiReaderException(string message, JsonNode? node) : base(message)
{
// This only includes line because using a char range causes tests to break due to CR/LF & LF differences
// See https://tools.ietf.org/html/rfc5147 for syntax
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
/// Defines an exception indicating OpenAPI Reader encountered an unsupported specification version while reading.
/// </summary>
[Serializable]
public class OpenApiUnsupportedSpecVersionException : Exception

Check warning on line 13 in src/Microsoft.OpenApi/Exceptions/OpenApiUnsupportedSpecVersionException.cs

View workflow job for this annotation

GitHub Actions / Build

Update this implementation of 'ISerializable' to conform to the recommended serialization pattern. Add a 'protected' constructor 'OpenApiUnsupportedSpecVersionException(SerializationInfo, StreamingContext)'. (https://rules.sonarsource.com/csharp/RSPEC-3925)
{
const string messagePattern = "OpenAPI specification version '{0}' is not supported.";

Expand All @@ -18,7 +18,7 @@
/// Initializes the <see cref="OpenApiUnsupportedSpecVersionException"/> class with a specification version.
/// </summary>
/// <param name="specificationVersion">Version that caused this exception to be thrown.</param>
public OpenApiUnsupportedSpecVersionException(string specificationVersion)
public OpenApiUnsupportedSpecVersionException(string? specificationVersion)
: base(string.Format(CultureInfo.InvariantCulture, messagePattern, specificationVersion))
{
this.SpecificationVersion = specificationVersion;
Expand All @@ -39,6 +39,6 @@
/// <summary>
/// The unsupported specification version.
/// </summary>
public string SpecificationVersion { get; }
public string? SpecificationVersion { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public OpenApiWriterException(string message)
/// </summary>
/// <param name="message">The plain text error message for this exception.</param>
/// <param name="innerException">The inner exception that is the cause of this exception to be thrown.</param>
public OpenApiWriterException(string message, Exception innerException)
public OpenApiWriterException(string message, Exception? innerException)
: base(message, innerException)
{
}
Expand Down
4 changes: 2 additions & 2 deletions src/Microsoft.OpenApi/Expressions/BodyExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public BodyExpression()
/// Initializes a new instance of the <see cref="BodyExpression"/> class.
/// </summary>
/// <param name="pointer">a JSON Pointer [RFC 6901](https://tools.ietf.org/html/rfc6901).</param>
public BodyExpression(JsonPointer pointer)
public BodyExpression(JsonPointer? pointer)
: base(pointer?.ToString())
{
Utils.CheckArgumentNull(pointer);
Expand All @@ -55,6 +55,6 @@ public override string Expression
/// <summary>
/// Gets the fragment string.
/// </summary>
public string Fragment { get => Value; }
public string? Fragment { get => Value; }
}
}
2 changes: 1 addition & 1 deletion src/Microsoft.OpenApi/Expressions/HeaderExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ public HeaderExpression(string token)
/// <summary>
/// Gets the token string.
/// </summary>
public string Token { get => Value; }
public string? Token { get => Value; }
}
}
2 changes: 1 addition & 1 deletion src/Microsoft.OpenApi/Expressions/PathExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ public PathExpression(string name)
/// <summary>
/// Gets the name string.
/// </summary>
public string Name { get => Value; }
public string? Name { get => Value; }
}
}
2 changes: 1 addition & 1 deletion src/Microsoft.OpenApi/Expressions/QueryExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ public QueryExpression(string name)
/// <summary>
/// Gets the name string.
/// </summary>
public string Name { get => Value; }
public string? Name { get => Value; }
}
}
4 changes: 2 additions & 2 deletions src/Microsoft.OpenApi/Expressions/RuntimeExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,15 @@ public override int GetHashCode()
/// <summary>
/// Equals implementation for IEquatable.
/// </summary>
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return Equals(obj as RuntimeExpression);
}

/// <summary>
/// Equals implementation for object of the same type.
/// </summary>
public bool Equals(RuntimeExpression obj)
public bool Equals(RuntimeExpression? obj)
{
return obj != null && obj.Expression == Expression;
}
Expand Down
Loading
Loading