Skip to content

fix: Remove operationId plural validation #162

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

Merged
merged 7 commits into from
Aug 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -513,4 +513,6 @@ dotnet_diagnostic.CA1848.severity = suggestion # Use the LoggerMessage delegate
dotnet_diagnostic.CA2254.severity = suggestion # Template should be a static expression - https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2254

dotnet_diagnostic.S1172.severity = none # False positive
dotnet_diagnostic.S3267.severity = none # Loop should be simplified by calling Select(x => x.Value)) - We dont like this rule because of readability/maintainability
dotnet_diagnostic.S3267.severity = none # Loop should be simplified by calling Select(x => x.Value)) - We dont like this rule because of readability/maintainability

dotnet_diagnostic.SA1414.Severity = none # Tuple types in signatures should have element names
8 changes: 4 additions & 4 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@
<ItemGroup Label="Code Analyzers">
<PackageReference Include="AsyncFixer" Version="1.5.1" PrivateAssets="All" />
<PackageReference Include="Asyncify" Version="0.9.7" PrivateAssets="All" />
<PackageReference Include="Meziantou.Analyzer" Version="1.0.701" PrivateAssets="All" />
<PackageReference Include="SecurityCodeScan.VS2019" Version="5.6.2" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Include="SonarAnalyzer.CSharp" Version="8.38.0.46746" PrivateAssets="All" />
<PackageReference Include="Meziantou.Analyzer" Version="1.0.717" PrivateAssets="All" />
<PackageReference Include="SecurityCodeScan.VS2019" Version="5.6.6" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="All" />
<PackageReference Include="SonarAnalyzer.CSharp" Version="8.44.0.52574" PrivateAssets="All" />
</ItemGroup>

</Project>
5 changes: 5 additions & 0 deletions src/Atc.Rest.ApiGenerator.CLI/ApiOptionsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ private static void ApplyValidationOverrides(
apiOptions.Validation.StrictMode = settings.StrictMode;
}

if (settings.OperationIdValidation)
{
apiOptions.Validation.OperationIdValidation = settings.OperationIdValidation;
}

if (settings.OperationIdCasingStyle.IsSet)
{
apiOptions.Validation.OperationIdCasingStyle = settings.OperationIdCasingStyle.Value;
Expand Down
2 changes: 1 addition & 1 deletion src/Atc.Rest.ApiGenerator.CLI/AtcApiNugetClientHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ namespace Atc.Rest.ApiGenerator.CLI;
public static class AtcApiNugetClientHelper
{
private const string BaseAddress = "https://atc-api.azurewebsites.net/nuget-search";
private static readonly ConcurrentDictionary<string, Version> Cache = new (StringComparer.Ordinal);
private static readonly ConcurrentDictionary<string, Version> Cache = new(StringComparer.Ordinal);

[SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "OK.")]
public static Version? GetLatestVersionForPackageId(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public static class ArgumentCommandConstants
public const string LongConfigurationAuthorization = "--useAuthorization";

public const string LongConfigurationValidateStrictMode = "--validate-strictMode";
public const string LongConfigurationValidateOperationIdValidation = "--validate-operationIdValidation";
public const string LongConfigurationValidateOperationIdCasingStyle = "--validate-operationIdCasingStyle";
public const string LongConfigurationValidateModelNameCasingStyle = "--validate-modelNameCasingStyle";
public const string LongConfigurationValidateModelPropertyNameCasingStyle = "--validate-modelPropertyNameCasingStyle";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,21 @@ public class BaseConfigurationCommandSettings : BaseCommandSettings
[Description("Use strictmode")]
public bool StrictMode { get; init; }

[CommandOption($"{ArgumentCommandConstants.LongConfigurationValidateOperationIdValidation}")]
[Description("Use operationId validation")]
public bool OperationIdValidation { get; init; }

[CommandOption($"{ArgumentCommandConstants.LongConfigurationValidateOperationIdCasingStyle} [OPERATIONIDCASINGSTYLE]")]
[CasingStyleDescription(Default = CasingStyle.CamelCase, Prefix = "Set casingStyle for operationId")]
public FlagValue<CasingStyle> OperationIdCasingStyle { get; init; } = new ();
public FlagValue<CasingStyle> OperationIdCasingStyle { get; init; } = new();

[CommandOption($"{ArgumentCommandConstants.LongConfigurationValidateModelNameCasingStyle} [MODELNAMECASINGSTYLE]")]
[CasingStyleDescription(Default = CasingStyle.PascalCase, Prefix = "Set casingStyle for model name")]
public FlagValue<CasingStyle> ModelNameCasingStyle { get; init; } = new ();
public FlagValue<CasingStyle> ModelNameCasingStyle { get; init; } = new();

[CommandOption($"{ArgumentCommandConstants.LongConfigurationValidateModelPropertyNameCasingStyle} [MODELPROPERTYNAMECASINGSTYLE]")]
[CasingStyleDescription(Default = CasingStyle.CamelCase, Prefix = "Set casingStyle for model property name")]
public FlagValue<CasingStyle> ModelPropertyNameCasingStyle { get; init; } = new ();
public FlagValue<CasingStyle> ModelPropertyNameCasingStyle { get; init; } = new();

[CommandOption($"{ArgumentCommandConstants.LongConfigurationAuthorization}")]
[Description("Use authorization")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public static PropertyDeclarationSyntax AddValidationAttributeFromSchemaFormatIf
OpenApiFormatTypeConstants.Email => propertyDeclaration.AddValidationAttributeEmail(schema),
OpenApiFormatTypeConstants.Uri => propertyDeclaration.AddValidationAttribute(new UriAttribute()),

_ => throw new NotImplementedException($"Schema Format '{schema.Format}' must be implemented.")
_ => throw new NotImplementedException($"Schema Format '{schema.Format}' must be implemented."),
};
}

Expand Down Expand Up @@ -165,7 +165,7 @@ schema.MinLength is null &&
{
OpenApiDataTypeConstants.Number when !schema.HasFormatType() => RangeAttributeDouble(propertyDeclaration, schema),
OpenApiDataTypeConstants.Integer when schema.HasFormatType() && schema.IsFormatTypeInt64() => RangeAttributeLong(propertyDeclaration, schema),
_ => RangeAttributeInt(propertyDeclaration, schema)
_ => RangeAttributeInt(propertyDeclaration, schema),
};
}

Expand Down
20 changes: 10 additions & 10 deletions src/Atc.Rest.ApiGenerator/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ internal static class StringExtensions
{
private const string AutoPropGetSetResultPattern = " { get; set; }";
private const string AutoPropGetResultPattern = " { get; }";
private static readonly Regex AutoPropGetSetRegex = new (@"\s*\{\s*get;\s*set;\s*}");
private static readonly Regex AutoPropGetRegex = new (@"\s*\{\s*get;\s*}");
private static readonly Regex AutoPropInitializerGetSetRegex = new (@"\s*\{ get; set; }\s*= \s*");
private static readonly Regex AutoPropInitializerGetRegex = new (@"\s*\{ get; }\s*= \s*");
private static readonly Regex AutoPublicLinesRegex = new (@"\s*;\s*public \s*");
private static readonly Regex AutoPrivateLinesRegex = new (@"\s*;\s*private \s*");
private static readonly Regex AutoCommentLinesRegex = new (@"\s*;\s*/// \s*");
private static readonly Regex AutoBracketSpacingStartRegex = new (@"(\S)({)(\S)");
private static readonly Regex AutoBracketSpacingEndRegex = new (@"(\S)(})(\S)");
private static readonly Regex ConstructorWithInheritResultRegex = new (@":\s*base\(result\)\s*\{\s*\}");
private static readonly Regex AutoPropGetSetRegex = new(@"\s*\{\s*get;\s*set;\s*}");
private static readonly Regex AutoPropGetRegex = new(@"\s*\{\s*get;\s*}");
private static readonly Regex AutoPropInitializerGetSetRegex = new(@"\s*\{ get; set; }\s*= \s*");
private static readonly Regex AutoPropInitializerGetRegex = new(@"\s*\{ get; }\s*= \s*");
private static readonly Regex AutoPublicLinesRegex = new(@"\s*;\s*public \s*");
private static readonly Regex AutoPrivateLinesRegex = new(@"\s*;\s*private \s*");
private static readonly Regex AutoCommentLinesRegex = new(@"\s*;\s*/// \s*");
private static readonly Regex AutoBracketSpacingStartRegex = new(@"(\S)({)(\S)");
private static readonly Regex AutoBracketSpacingEndRegex = new(@"(\S)(})(\S)");
private static readonly Regex ConstructorWithInheritResultRegex = new(@":\s*base\(result\)\s*\{\s*\}");

private static readonly string[] LineBreaks = { "\r\n", "\r", "\n" };

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static SuppressMessageAttribute Create(
{
// TODO: Add all rules
1062 => new SuppressMessageAttribute("Design", "CA1062:Validate arguments of public methods") { Justification = justification },
_ => throw new NotImplementedException($"Rule for CA{checkId} must be implemented.")
_ => throw new NotImplementedException($"Rule for CA{checkId} must be implemented."),
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ namespace Atc.Rest.ApiGenerator.Helpers;
public static class AtcApiNugetClientHelper
{
private const string BaseAddress = "https://atc-api.azurewebsites.net/nuget-search";
private static readonly ConcurrentDictionary<string, Version> Cache = new (StringComparer.Ordinal);
private static readonly ConcurrentDictionary<string, Version> Cache = new(StringComparer.Ordinal);

[SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "OK.")]
public static Version? GetLatestVersionForPackageId(
Expand Down
2 changes: 1 addition & 1 deletion src/Atc.Rest.ApiGenerator/Helpers/GenerateCodeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ internal static string GetTrailingChar(
TrailingCharType.Comma => ",",
TrailingCharType.SemiColon => ";",
TrailingCharType.Colon => ":",
_ => throw new ArgumentOutOfRangeException(nameof(trailingChar), trailingChar, null)
_ => throw new ArgumentOutOfRangeException(nameof(trailingChar), trailingChar, null),
};
}
2 changes: 1 addition & 1 deletion src/Atc.Rest.ApiGenerator/Helpers/GenerateHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Atc.Rest.ApiGenerator.Helpers;

public static class GenerateHelper
{
private static readonly Version AtcToolVersion = new (1, 1, 405, 0); // TODO: Fix version
private static readonly Version AtcToolVersion = new(1, 1, 405, 0); // TODO: Fix version

public static Version GetAtcVersion()
{
Expand Down
4 changes: 1 addition & 3 deletions src/Atc.Rest.ApiGenerator/Helpers/HttpClientHelper.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
using System.Diagnostics;

namespace Atc.Rest.ApiGenerator.Helpers;

public static class HttpClientHelper
{
private static readonly ConcurrentDictionary<string, string> Cache = new (StringComparer.Ordinal);
private static readonly ConcurrentDictionary<string, string> Cache = new(StringComparer.Ordinal);

public static string GetAsString(
ILogger logger,
Expand Down
38 changes: 19 additions & 19 deletions src/Atc.Rest.ApiGenerator/Helpers/NugetPackageReferenceHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ public static class NugetPackageReferenceHelper

var packageReference = new List<Tuple<string, string, string?>>
{
new ("Atc", atcVersion, null),
new ("Atc.Rest", atcVersion, null),
new("Atc", atcVersion, null),
new("Atc.Rest", atcVersion, null),
};

if (useRestExtended)
{
packageReference.Add(new Tuple<string, string, string?>("Atc.Rest.Extended", atcVersion, null));
packageReference.Add(new Tuple<string, string, string?>("FluentValidation.AspNetCore", "11.0.0", null));
packageReference.Add(new Tuple<string, string, string?>("Microsoft.ApplicationInsights.AspNetCore", "2.20.0", null));
packageReference.Add(new Tuple<string, string, string?>("Microsoft.AspNetCore.Authentication.JwtBearer", "6.0.4", null));
packageReference.Add(new Tuple<string, string, string?>("FluentValidation.AspNetCore", "11.1.3", null));
packageReference.Add(new Tuple<string, string, string?>("Microsoft.ApplicationInsights.AspNetCore", "2.21.0", null));
packageReference.Add(new Tuple<string, string, string?>("Microsoft.AspNetCore.Authentication.JwtBearer", "6.0.7", null));
packageReference.Add(new Tuple<string, string, string?>("Microsoft.AspNetCore.Mvc.Versioning", "5.0.0", null));
packageReference.Add(new Tuple<string, string, string?>("Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer", "5.0.0", null));
packageReference.Add(new Tuple<string, string, string?>("Swashbuckle.AspNetCore", "6.3.1", null));
packageReference.Add(new Tuple<string, string, string?>("Swashbuckle.AspNetCore", "6.4.0", null));
}

return packageReference;
Expand All @@ -33,8 +33,8 @@ public static class NugetPackageReferenceHelper

var packageReference = new List<Tuple<string, string, string?>>
{
new ("Atc", atcVersion, null),
new ("Atc.Rest", atcVersion, null),
new("Atc", atcVersion, null),
new("Atc.Rest", atcVersion, null),
};

return packageReference;
Expand All @@ -46,8 +46,8 @@ public static class NugetPackageReferenceHelper

var packageReference = new List<Tuple<string, string, string?>>
{
new ("Atc", atcVersion, null),
new ("Atc.Rest.Client", "1.0.36", null),
new("Atc", atcVersion, null),
new("Atc.Rest.Client", "1.0.36", null),
};

return packageReference;
Expand All @@ -57,11 +57,11 @@ public static class NugetPackageReferenceHelper
{
var packageReference = new List<Tuple<string, string, string?>>
{
new ("Atc.XUnit", "2.0.93", null),
new ("AutoFixture", "4.17.0", null),
new ("AutoFixture.AutoNSubstitute", "4.17.0", null),
new ("AutoFixture.Xunit2", "4.17.0", null),
new ("FluentAssertions", "6.5.1", null),
new("Atc.XUnit", "2.0.93", null),
new("AutoFixture", "4.17.0", null),
new("AutoFixture.AutoNSubstitute", "4.17.0", null),
new("AutoFixture.Xunit2", "4.17.0", null),
new("FluentAssertions", "6.5.1", null),
};

if (useMvc)
Expand All @@ -71,10 +71,10 @@ public static class NugetPackageReferenceHelper

packageReference.AddRange(new List<Tuple<string, string, string?>>
{
new ("Microsoft.NET.Test.Sdk", "17.1.0", null),
new ("NSubstitute", "4.3.0", null),
new ("xunit", "2.4.1", null),
new ("xunit.runner.visualstudio", "2.4.3", "<PrivateAssets>all</PrivateAssets>\n<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>"),
new("Microsoft.NET.Test.Sdk", "17.1.0", null),
new("NSubstitute", "4.3.0", null),
new("xunit", "2.4.1", null),
new("xunit.runner.visualstudio", "2.4.3", "<PrivateAssets>all</PrivateAssets>\n<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>"),
});

return packageReference;
Expand Down
2 changes: 1 addition & 1 deletion src/Atc.Rest.ApiGenerator/Helpers/OpenApiDocumentHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public static Tuple<OpenApiDocument, OpenApiDiagnostic, FileInfo> CombineAndGetA
{
0 => throw new IOException("Api specification file don't exist in folder."),
1 => new FileInfo(docFiles.First()),
_ => CreateCombineApiDocumentFile(specificationPath)
_ => CreateCombineApiDocumentFile(specificationPath),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,29 +240,32 @@ private static List<LogKeyValueItem> ValidateOperations(
}
}

foreach (var (operationKey, operationValue) in pathValue.Operations)
if (validationOptions.OperationIdValidation)
{
// Validate Response Schema
var responseModelSchema = operationValue.GetModelSchemaFromResponse();
if (responseModelSchema is not null)
foreach (var (operationKey, operationValue) in pathValue.Operations)
{
if (operationValue.IsOperationIdPluralized(operationKey))
// Validate Response Schema
var responseModelSchema = operationValue.GetModelSchemaFromResponse();
if (responseModelSchema is not null)
{
if (!IsModelOfTypeArray(responseModelSchema, modelSchemas))
if (operationValue.IsOperationIdPluralized(operationKey))
{
logItems.Add(LogItemHelper.Create(logCategory, ValidationRuleNameConstants.Operation08, $"OperationId '{operationValue.OperationId}' is not singular - Response model is defined as a single item."));
if (!IsModelOfTypeArray(responseModelSchema, modelSchemas))
{
logItems.Add(LogItemHelper.Create(logCategory, ValidationRuleNameConstants.Operation08, $"OperationId '{operationValue.OperationId}' is not singular - Response model is defined as a single item."));
}
}
}
else
{
if (IsModelOfTypeArray(responseModelSchema, modelSchemas))
else
{
logItems.Add(LogItemHelper.Create(logCategory, ValidationRuleNameConstants.Operation09, $"OperationId '{operationValue.OperationId}' is not pluralized - Response model is defined as an array."));
if (IsModelOfTypeArray(responseModelSchema, modelSchemas))
{
logItems.Add(LogItemHelper.Create(logCategory, ValidationRuleNameConstants.Operation09, $"OperationId '{operationValue.OperationId}' is not pluralized - Response model is defined as an array."));
}
}
}
}

//// TO-DO Validate RequestBody Schema
//// TO-DO Validate RequestBody Schema
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -897,7 +897,7 @@ private static string PropertyValueGenerator(
"Uri" => ValueTypeTestPropertiesHelper.CreateValueUri(useForBadRequest),
"Email" => ValueTypeTestPropertiesHelper.CreateValueEmail(useForBadRequest),
"Array" when parameter.In == ParameterLocation.Query => ValueTypeTestPropertiesHelper.CreateValueArray(parameter.Name, parameter.Schema.Items, parameter.In, useForBadRequest, 3),
_ => PropertyValueGeneratorTypeResolver(parameter, componentsSchemas, useForBadRequest)
_ => PropertyValueGeneratorTypeResolver(parameter, componentsSchemas, useForBadRequest),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ public static string PropertyValueGenerator(
"Guid" => ValueTypeTestPropertiesHelper.CreateValueGuid(useForBadRequest, itemNumber),
"Uri" => ValueTypeTestPropertiesHelper.CreateValueUri(useForBadRequest),
"Email" => ValueTypeTestPropertiesHelper.CreateValueEmail(useForBadRequest),
_ => PropertyValueGeneratorTypeResolver(schema, componentsSchemas, useForBadRequest)
_ => PropertyValueGeneratorTypeResolver(schema, componentsSchemas, useForBadRequest),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public static string Number(
{
OpenApiDataTypeConstants.Number when !schema.HasFormatType() => CreateNumberDouble(schema),
OpenApiDataTypeConstants.Integer when schema.HasFormatType() && schema.IsFormatTypeInt64() => CreateNumberLong(schema),
_ => CreateNumberInt(schema)
_ => CreateNumberInt(schema),
};
}

Expand Down Expand Up @@ -335,6 +335,6 @@ private static string CreateValueArrayItem(
"Guid" => CreateValueGuid(useForBadRequest, itemNumber),
"Uri" => CreateValueUri(useForBadRequest),
"Email" => CreateValueEmail(useForBadRequest, itemNumber),
_ => throw new NotSupportedException($"PropertyValueGenerator: {name} - array of ({itemSchema.GetDataType()})")
_ => throw new NotSupportedException($"PropertyValueGenerator: {name} - array of ({itemSchema.GetDataType()})"),
};
}
Loading