Skip to content
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
20 changes: 8 additions & 12 deletions src/OpenApi/src/Extensions/JsonNodeSchemaExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,24 +115,20 @@ internal static void ApplyValidationAttributes(this JsonNode schema, IEnumerable
}
else if (attribute is MaxLengthAttribute maxLengthAttribute)
{
var targetKey = schema[OpenApiSchemaKeywords.TypeKeyword]?.GetValue<string>() == "array" ? OpenApiSchemaKeywords.MaxItemsKeyword : OpenApiSchemaKeywords.MaxLengthKeyword;
schema[targetKey] = maxLengthAttribute.Length;
var isArray = MapJsonNodeToSchemaType(schema[OpenApiSchemaKeywords.TypeKeyword]) is { } schemaTypes && schemaTypes.HasFlag(JsonSchemaType.Array);
var key = isArray ? OpenApiSchemaKeywords.MaxItemsKeyword : OpenApiSchemaKeywords.MaxLengthKeyword;
schema[key] = maxLengthAttribute.Length;
}
else if (attribute is MinLengthAttribute minLengthAttribute)
{
if (MapJsonNodeToSchemaType(schema[OpenApiSchemaKeywords.TypeKeyword]) is { } schemaTypes &&
schemaTypes.HasFlag(JsonSchemaType.Array))
{
schema[OpenApiSchemaKeywords.MinItemsKeyword] = minLengthAttribute.Length;
}
else
{
schema[OpenApiSchemaKeywords.MinLengthKeyword] = minLengthAttribute.Length;
}
var isArray = MapJsonNodeToSchemaType(schema[OpenApiSchemaKeywords.TypeKeyword]) is { } schemaTypes && schemaTypes.HasFlag(JsonSchemaType.Array);
var key = isArray ? OpenApiSchemaKeywords.MinItemsKeyword : OpenApiSchemaKeywords.MinLengthKeyword;
schema[key] = minLengthAttribute.Length;
}
else if (attribute is LengthAttribute lengthAttribute)
{
var targetKeySuffix = schema[OpenApiSchemaKeywords.TypeKeyword]?.GetValue<string>() == "array" ? "Items" : "Length";
var isArray = MapJsonNodeToSchemaType(schema[OpenApiSchemaKeywords.TypeKeyword]) is { } schemaTypes && schemaTypes.HasFlag(JsonSchemaType.Array);
var targetKeySuffix = isArray ? "Items" : "Length";
schema[$"min{targetKeySuffix}"] = lengthAttribute.MinimumLength;
schema[$"max{targetKeySuffix}"] = lengthAttribute.MaximumLength;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,35 @@ await VerifyOpenApiDocument(builder, document =>
Assert.Equal("name", property.Key);
Assert.Equal(JsonSchemaType.String | JsonSchemaType.Null, property.Value.Type);
Assert.Equal(5, property.Value.MinLength);
Assert.Equal(10, property.Value.MaxLength);
Assert.Null(property.Value.Default);
},
property =>
{
Assert.Equal("description", property.Key);
Assert.Equal(JsonSchemaType.String | JsonSchemaType.Null, property.Value.Type);
Assert.Equal(5, property.Value.MinLength);
Assert.Equal(10, property.Value.MaxLength);
},
property =>
{
Assert.Equal("isPrivate", property.Key);
Assert.Equal(JsonSchemaType.Boolean, property.Value.Type);
Assert.True(property.Value.Default.GetValue<bool>());
},
property =>
{
Assert.Equal("items", property.Key);
Assert.Equal(JsonSchemaType.Array | JsonSchemaType.Null, property.Value.Type);
Assert.Equal(10, property.Value.MaxItems);
},
property =>
{
Assert.Equal("tags", property.Key);
Assert.Equal(JsonSchemaType.Array | JsonSchemaType.Null, property.Value.Type);
Assert.Equal(5, property.Value.MinItems);
Assert.Equal(10, property.Value.MaxItems);
});

});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,34 @@ await VerifyOpenApiDocument(builder, document =>
Assert.Equal("name", property.Key);
Assert.Equal(JsonSchemaType.String | JsonSchemaType.Null, property.Value.Type);
Assert.Equal(5, property.Value.MinLength);
Assert.Equal(10, property.Value.MaxLength);
Assert.Null(property.Value.Default);
},
property =>
{
Assert.Equal("description", property.Key);
Assert.Equal(JsonSchemaType.String | JsonSchemaType.Null, property.Value.Type);
Assert.Equal(5, property.Value.MinLength);
Assert.Equal(10, property.Value.MaxLength);
},
property =>
{
Assert.Equal("isPrivate", property.Key);
Assert.Equal(JsonSchemaType.Boolean, property.Value.Type);
Assert.True(property.Value.Default.GetValue<bool>());
},
property =>
{
Assert.Equal("items", property.Key);
Assert.Equal(JsonSchemaType.Array | JsonSchemaType.Null, property.Value.Type);
Assert.Equal(10, property.Value.MaxItems);
},
property =>
{
Assert.Equal("tags", property.Key);
Assert.Equal(JsonSchemaType.Array | JsonSchemaType.Null, property.Value.Type);
Assert.Equal(5, property.Value.MinItems);
Assert.Equal(10, property.Value.MaxItems);
});

});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,29 @@ internal class ProjectBoard
public int Id { get; set; }

[MinLength(5)]
[MaxLength(10)]
[DefaultValue(null)]
[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Used in tests.")]
public string? Name { get; set; }

[Length(5, 10)]
[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Used in tests.")]
public string? Description { get; set; }

[DefaultValue(true)]
public required bool IsPrivate { get; set; }

[MaxLength(10)]
[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Used in tests.")]
public IList<ProjectBoardItem>? Items { get; set; }

[Length(5, 10)]
[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Used in tests.")]
public IEnumerable<string>? Tags { get; set; }
}

internal sealed record ProjectBoardItem(string Name);

#nullable restore

internal class Account
Expand Down
Loading