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
14 changes: 2 additions & 12 deletions src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiSerializable
/// <summary>
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
/// </summary>
public decimal? V31ExclusiveMaximum { get; }
public decimal? ExclusiveMaximum { get; }

/// <summary>
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
/// </summary>
public decimal? V31ExclusiveMinimum { get; }
public decimal? ExclusiveMinimum { get; }

/// <summary>
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
Expand Down Expand Up @@ -90,21 +90,11 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiSerializable
/// </summary>
public decimal? Maximum { get; }

/// <summary>
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
/// </summary>
public bool? ExclusiveMaximum { get; }

/// <summary>
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
/// </summary>
public decimal? Minimum { get; }

/// <summary>
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
/// </summary>
public bool? ExclusiveMinimum { get; }

/// <summary>
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
/// </summary>
Expand Down
170 changes: 137 additions & 33 deletions src/Microsoft.OpenApi/Models/OpenApiSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,63 @@ public class OpenApiSchema : IOpenApiReferenceable, IOpenApiExtensible, IOpenApi
/// <inheritdoc />
public IDictionary<string, IOpenApiSchema> Definitions { get; set; }

private decimal? _exclusiveMaximum;
/// <inheritdoc />
public decimal? V31ExclusiveMaximum { get; set; }
public decimal? ExclusiveMaximum
{
get
{
if (_exclusiveMaximum.HasValue)
{
return _exclusiveMaximum;
}
if (IsExclusiveMaximum == true && _maximum.HasValue)
{
return _maximum;
}
return null;
}
set
{
_exclusiveMaximum = value;
IsExclusiveMaximum = value != null;
}
}

/// <summary>
/// Compatibility property for OpenAPI 3.0 or earlier serialization of the exclusive maximum value.
/// </summary>
/// DO NOT CHANGE THE VISIBILITY OF THIS PROPERTY TO PUBLIC
internal bool? IsExclusiveMaximum { get; set; }

private decimal? _exclusiveMinimum;
/// <inheritdoc />
public decimal? V31ExclusiveMinimum { get; set; }
public decimal? ExclusiveMinimum
{
get
{
if (_exclusiveMinimum.HasValue)
{
return _exclusiveMinimum;
}
if (IsExclusiveMinimum == true && _minimum.HasValue)
{
return _minimum;
}
return null;
}
set
{
_exclusiveMinimum = value;
IsExclusiveMinimum = value != null;
}
}

/// <summary>
/// Compatibility property for OpenAPI 3.0 or earlier serialization of the exclusive minimum value.
/// </summary>
/// DO NOT CHANGE THE VISIBILITY OF THIS PROPERTY TO PUBLIC
internal bool? IsExclusiveMinimum { get; set; }

/// <inheritdoc />
public bool UnEvaluatedProperties { get; set; }
Expand All @@ -65,17 +117,42 @@ public class OpenApiSchema : IOpenApiReferenceable, IOpenApiExtensible, IOpenApi
/// <inheritdoc />
public string Description { get; set; }

private decimal? _maximum;
/// <inheritdoc />
public decimal? Maximum { get; set; }

/// <inheritdoc />
public bool? ExclusiveMaximum { get; set; }
public decimal? Maximum
{
get
{
if (IsExclusiveMaximum == true)
{
return null;
}
return _maximum;
}
set
{
_maximum = value;
}
}

/// <inheritdoc />
public decimal? Minimum { get; set; }
private decimal? _minimum;

/// <inheritdoc />
public bool? ExclusiveMinimum { get; set; }
public decimal? Minimum
{
get
{
if (IsExclusiveMinimum == true)
{
return null;
}
return _minimum;
}
set
{
_minimum = value;
}
}

/// <inheritdoc />
public int? MaxLength { get; set; }
Expand Down Expand Up @@ -201,15 +278,18 @@ internal OpenApiSchema(IOpenApiSchema schema)
DynamicRef = schema.DynamicRef ?? DynamicRef;
Definitions = schema.Definitions != null ? new Dictionary<string, IOpenApiSchema>(schema.Definitions) : null;
UnevaluatedProperties = schema.UnevaluatedProperties;
V31ExclusiveMaximum = schema.V31ExclusiveMaximum ?? V31ExclusiveMaximum;
V31ExclusiveMinimum = schema.V31ExclusiveMinimum ?? V31ExclusiveMinimum;
ExclusiveMaximum = schema.ExclusiveMaximum ?? ExclusiveMaximum;
ExclusiveMinimum = schema.ExclusiveMinimum ?? ExclusiveMinimum;
if (schema is OpenApiSchema eMSchema)
{
IsExclusiveMaximum = eMSchema.IsExclusiveMaximum;
IsExclusiveMinimum = eMSchema.IsExclusiveMinimum;
}
Type = schema.Type ?? Type;
Format = schema.Format ?? Format;
Description = schema.Description ?? Description;
Maximum = schema.Maximum ?? Maximum;
ExclusiveMaximum = schema.ExclusiveMaximum ?? ExclusiveMaximum;
Minimum = schema.Minimum ?? Minimum;
ExclusiveMinimum = schema.ExclusiveMinimum ?? ExclusiveMinimum;
MaxLength = schema.MaxLength ?? MaxLength;
MinLength = schema.MinLength ?? MinLength;
Pattern = schema.Pattern ?? Pattern;
Expand Down Expand Up @@ -257,6 +337,44 @@ public void SerializeAsV3(IOpenApiWriter writer)
SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer));
}

private static void SerializeBounds(IOpenApiWriter writer, OpenApiSpecVersion version, string propertyName, string exclusivePropertyName, string isExclusivePropertyName, decimal? value, decimal? exclusiveValue, bool? isExclusiveValue)
{
if (version >= OpenApiSpecVersion.OpenApi3_1)
{
if (exclusiveValue.HasValue)
{
// was explicitly set in the document or object model
writer.WriteProperty(exclusivePropertyName, exclusiveValue.Value);
}
else if (isExclusiveValue == true && value.HasValue)
{
// came from parsing an old document
writer.WriteProperty(exclusivePropertyName, value);
}
else if (value.HasValue)
{
// was explicitly set in the document or object model
writer.WriteProperty(propertyName, value);
}
}
else
{
if (exclusiveValue.HasValue)
{
// was explicitly set in a new document being downcast or object model
writer.WriteProperty(propertyName, exclusiveValue.Value);
writer.WriteProperty(isExclusivePropertyName, true);
}
else if (value.HasValue)
{
// came from parsing an old document, we're just mirroring the information
writer.WriteProperty(propertyName, value);
if (isExclusiveValue.HasValue)
writer.WriteProperty(isExclusivePropertyName, isExclusiveValue.Value);
}
}
}

private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version,
Action<IOpenApiWriter, IOpenApiSerializable> callback)
{
Expand All @@ -274,16 +392,12 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version
writer.WriteProperty(OpenApiConstants.MultipleOf, MultipleOf);

// maximum
writer.WriteProperty(OpenApiConstants.Maximum, Maximum);

// exclusiveMaximum
writer.WriteProperty(OpenApiConstants.ExclusiveMaximum, ExclusiveMaximum);
SerializeBounds(writer, version, OpenApiConstants.Maximum, OpenApiConstants.ExclusiveMaximum, OpenApiConstants.V31ExclusiveMaximum, Maximum, ExclusiveMaximum, IsExclusiveMaximum);

// minimum
writer.WriteProperty(OpenApiConstants.Minimum, Minimum);

// exclusiveMinimum
writer.WriteProperty(OpenApiConstants.ExclusiveMinimum, ExclusiveMinimum);
SerializeBounds(writer, version, OpenApiConstants.Minimum, OpenApiConstants.ExclusiveMinimum, OpenApiConstants.V31ExclusiveMinimum, Minimum, ExclusiveMinimum, IsExclusiveMinimum);

// maxLength
writer.WriteProperty(OpenApiConstants.MaxLength, MaxLength);
Expand Down Expand Up @@ -407,8 +521,6 @@ internal void WriteJsonSchemaKeywords(IOpenApiWriter writer)
writer.WriteOptionalMap(OpenApiConstants.Defs, Definitions, (w, s) => s.SerializeAsV31(w));
writer.WriteProperty(OpenApiConstants.DynamicRef, DynamicRef);
writer.WriteProperty(OpenApiConstants.DynamicAnchor, DynamicAnchor);
writer.WriteProperty(OpenApiConstants.V31ExclusiveMaximum, V31ExclusiveMaximum);
writer.WriteProperty(OpenApiConstants.V31ExclusiveMinimum, V31ExclusiveMinimum);
writer.WriteProperty(OpenApiConstants.UnevaluatedProperties, UnevaluatedProperties, false);
writer.WriteOptionalCollection(OpenApiConstants.Examples, Examples, (nodeWriter, s) => nodeWriter.WriteAny(s));
writer.WriteOptionalMap(OpenApiConstants.PatternProperties, PatternProperties, (w, s) => s.SerializeAsV31(w));
Expand Down Expand Up @@ -438,16 +550,12 @@ internal void WriteAsItemsProperties(IOpenApiWriter writer)
writer.WriteOptionalObject(OpenApiConstants.Default, Default, (w, d) => w.WriteAny(d));

// maximum
writer.WriteProperty(OpenApiConstants.Maximum, Maximum);

// exclusiveMaximum
writer.WriteProperty(OpenApiConstants.ExclusiveMaximum, ExclusiveMaximum);
SerializeBounds(writer, OpenApiSpecVersion.OpenApi2_0, OpenApiConstants.Maximum, OpenApiConstants.ExclusiveMaximum, OpenApiConstants.V31ExclusiveMaximum, Maximum, ExclusiveMaximum, IsExclusiveMaximum);

// minimum
writer.WriteProperty(OpenApiConstants.Minimum, Minimum);

// exclusiveMinimum
writer.WriteProperty(OpenApiConstants.ExclusiveMinimum, ExclusiveMinimum);
SerializeBounds(writer, OpenApiSpecVersion.OpenApi2_0, OpenApiConstants.Minimum, OpenApiConstants.ExclusiveMinimum, OpenApiConstants.V31ExclusiveMinimum, Minimum, ExclusiveMinimum, IsExclusiveMinimum);

// maxLength
writer.WriteProperty(OpenApiConstants.MaxLength, MaxLength);
Expand Down Expand Up @@ -522,16 +630,12 @@ private void SerializeAsV2(
writer.WriteProperty(OpenApiConstants.MultipleOf, MultipleOf);

// maximum
writer.WriteProperty(OpenApiConstants.Maximum, Maximum);

// exclusiveMaximum
writer.WriteProperty(OpenApiConstants.ExclusiveMaximum, ExclusiveMaximum);
SerializeBounds(writer, OpenApiSpecVersion.OpenApi2_0, OpenApiConstants.Maximum, OpenApiConstants.ExclusiveMaximum, OpenApiConstants.V31ExclusiveMaximum, Maximum, ExclusiveMaximum, IsExclusiveMaximum);

// minimum
writer.WriteProperty(OpenApiConstants.Minimum, Minimum);

// exclusiveMinimum
writer.WriteProperty(OpenApiConstants.ExclusiveMinimum, ExclusiveMinimum);
SerializeBounds(writer, OpenApiSpecVersion.OpenApi2_0, OpenApiConstants.Minimum, OpenApiConstants.ExclusiveMinimum, OpenApiConstants.V31ExclusiveMinimum, Minimum, ExclusiveMinimum, IsExclusiveMinimum);

// maxLength
writer.WriteProperty(OpenApiConstants.MaxLength, MaxLength);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ public string Description
/// <inheritdoc/>
public IDictionary<string, IOpenApiSchema> Definitions { get => Target?.Definitions; }
/// <inheritdoc/>
public decimal? V31ExclusiveMaximum { get => Target?.V31ExclusiveMaximum; }
public decimal? ExclusiveMaximum { get => Target?.ExclusiveMaximum; }
/// <inheritdoc/>
public decimal? V31ExclusiveMinimum { get => Target?.V31ExclusiveMinimum; }
public decimal? ExclusiveMinimum { get => Target?.ExclusiveMinimum; }
/// <inheritdoc/>
public bool UnEvaluatedProperties { get => Target?.UnEvaluatedProperties ?? false; }
/// <inheritdoc/>
Expand All @@ -80,12 +80,8 @@ public string Description
/// <inheritdoc/>
public decimal? Maximum { get => Target?.Maximum; }
/// <inheritdoc/>
public bool? ExclusiveMaximum { get => Target?.ExclusiveMaximum; }
/// <inheritdoc/>
public decimal? Minimum { get => Target?.Minimum; }
/// <inheritdoc/>
public bool? ExclusiveMinimum { get => Target?.ExclusiveMinimum; }
/// <inheritdoc/>
public int? MaxLength { get => Target?.MaxLength; }
/// <inheritdoc/>
public int? MinLength { get => Target?.MinLength; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ internal static partial class OpenApiV2Deserializer
},
{
"exclusiveMaximum",
(o, n, _) => GetOrCreateSchema(o).ExclusiveMaximum = bool.Parse(n.GetScalarValue())
(o, n, _) => GetOrCreateSchema(o).IsExclusiveMaximum = bool.Parse(n.GetScalarValue())
},
{
"minimum",
(o, n, _) => GetOrCreateSchema(o).Minimum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MinValue)
},
{
"exclusiveMinimum",
(o, n, _) => GetOrCreateSchema(o).ExclusiveMinimum = bool.Parse(n.GetScalarValue())
(o, n, _) => GetOrCreateSchema(o).IsExclusiveMinimum = bool.Parse(n.GetScalarValue())
},
{
"maxLength",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ internal static partial class OpenApiV2Deserializer
},
{
"exclusiveMaximum",
(o, n, _) => o.ExclusiveMaximum = bool.Parse(n.GetScalarValue())
(o, n, _) => o.IsExclusiveMaximum = bool.Parse(n.GetScalarValue())
},
{
"minimum",
(o, n, _) => o.Minimum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MinValue)
},
{
"exclusiveMinimum",
(o, n, _) => o.ExclusiveMinimum = bool.Parse(n.GetScalarValue())
(o, n, _) => o.IsExclusiveMinimum = bool.Parse(n.GetScalarValue())
},
{
"maxLength",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ internal static partial class OpenApiV3Deserializer
},
{
"exclusiveMaximum",
(o, n, _) => o.ExclusiveMaximum = bool.Parse(n.GetScalarValue())
(o, n, _) => o.IsExclusiveMaximum = bool.Parse(n.GetScalarValue())
},
{
"minimum",
(o, n, _) => o.Minimum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MinValue)
},
{
"exclusiveMinimum",
(o, n, _) => o.ExclusiveMinimum = bool.Parse(n.GetScalarValue())
(o, n, _) => o.IsExclusiveMinimum = bool.Parse(n.GetScalarValue())
},
{
"maxLength",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,15 @@ internal static partial class OpenApiV31Deserializer
},
{
"exclusiveMaximum",
(o, n, _) => o.V31ExclusiveMaximum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MaxValue)
(o, n, _) => o.ExclusiveMaximum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MaxValue)
},
{
"minimum",
(o, n, _) => o.Minimum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MinValue)
},
{
"exclusiveMinimum",
(o, n, _) => o.V31ExclusiveMinimum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MaxValue)
(o, n, _) => o.ExclusiveMinimum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MaxValue)
},
{
"maxLength",
Expand Down
Loading