|
5 | 5 | using System.Collections.Generic;
|
6 | 6 | using System.Linq;
|
7 | 7 | using System.Text.Json.Nodes;
|
| 8 | +using Microsoft.OpenApi.Extensions; |
8 | 9 | using Microsoft.OpenApi.Helpers;
|
9 | 10 | using Microsoft.OpenApi.Interfaces;
|
10 | 11 | using Microsoft.OpenApi.Writers;
|
@@ -90,7 +91,7 @@ public class OpenApiSchema : IOpenApiAnnotatable, IOpenApiExtensible, IOpenApiRe
|
90 | 91 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
|
91 | 92 | /// Value MUST be a string in V2 and V3.
|
92 | 93 | /// </summary>
|
93 |
| - public virtual object Type { get; set; } |
| 94 | + public virtual JsonSchemaType? Type { get; set; } |
94 | 95 |
|
95 | 96 | /// <summary>
|
96 | 97 | /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
|
@@ -367,7 +368,7 @@ public OpenApiSchema(OpenApiSchema schema)
|
367 | 368 | UnevaluatedProperties = schema?.UnevaluatedProperties ?? UnevaluatedProperties;
|
368 | 369 | V31ExclusiveMaximum = schema?.V31ExclusiveMaximum ?? V31ExclusiveMaximum;
|
369 | 370 | V31ExclusiveMinimum = schema?.V31ExclusiveMinimum ?? V31ExclusiveMinimum;
|
370 |
| - Type = DeepCloneType(schema?.Type); |
| 371 | + Type = schema?.Type ?? Type; |
371 | 372 | Format = schema?.Format ?? Format;
|
372 | 373 | Description = schema?.Description ?? Description;
|
373 | 374 | Maximum = schema?.Maximum ?? Maximum;
|
@@ -590,7 +591,7 @@ internal void WriteV31Properties(IOpenApiWriter writer)
|
590 | 591 | internal void WriteAsItemsProperties(IOpenApiWriter writer)
|
591 | 592 | {
|
592 | 593 | // type
|
593 |
| - writer.WriteProperty(OpenApiConstants.Type, (string)Type); |
| 594 | + writer.WriteProperty(OpenApiConstants.Type, OpenApiTypeMapper.ToIdentifier(Type)); |
594 | 595 |
|
595 | 596 | // format
|
596 | 597 | if (string.IsNullOrEmpty(Format))
|
@@ -670,14 +671,7 @@ internal void SerializeAsV2(
|
670 | 671 | writer.WriteStartObject();
|
671 | 672 |
|
672 | 673 | // type
|
673 |
| - if (Type is string[] array) |
674 |
| - { |
675 |
| - DowncastTypeArrayToV2OrV3(array, writer, OpenApiSpecVersion.OpenApi2_0); |
676 |
| - } |
677 |
| - else |
678 |
| - { |
679 |
| - writer.WriteProperty(OpenApiConstants.Type, (string)Type); |
680 |
| - } |
| 674 | + SerializeTypeProperty(Type, writer, OpenApiSpecVersion.OpenApi2_0); |
681 | 675 |
|
682 | 676 | // description
|
683 | 677 | writer.WriteProperty(OpenApiConstants.Description, Description);
|
@@ -806,88 +800,112 @@ internal void SerializeAsV2(
|
806 | 800 | writer.WriteEndObject();
|
807 | 801 | }
|
808 | 802 |
|
809 |
| - private void SerializeTypeProperty(object type, IOpenApiWriter writer, OpenApiSpecVersion version) |
| 803 | + private void SerializeTypeProperty(JsonSchemaType? type, IOpenApiWriter writer, OpenApiSpecVersion version) |
810 | 804 | {
|
811 |
| - if (type?.GetType() == typeof(string)) |
| 805 | + var flagsCount = CountEnumSetFlags(type); |
| 806 | + if (flagsCount is 1) |
812 | 807 | {
|
813 | 808 | // check whether nullable is true for upcasting purposes
|
814 |
| - if (Nullable || Extensions.ContainsKey(OpenApiConstants.NullableExtension)) |
| 809 | + if (version is OpenApiSpecVersion.OpenApi3_1 && (Nullable || Extensions.ContainsKey(OpenApiConstants.NullableExtension))) |
815 | 810 | {
|
816 |
| - // create a new array and insert the type and "null" as values |
817 |
| - Type = new[] { (string)Type, OpenApiConstants.Null }; |
| 811 | + UpCastSchemaTypeToV31(type, writer); |
818 | 812 | }
|
819 | 813 | else
|
820 | 814 | {
|
821 |
| - writer.WriteProperty(OpenApiConstants.Type, (string)Type); |
| 815 | + writer.WriteProperty(OpenApiConstants.Type, OpenApiTypeMapper.ToIdentifier(type)); |
822 | 816 | }
|
823 | 817 | }
|
824 |
| - if (Type is string[] array) |
| 818 | + else if(flagsCount > 1) |
825 | 819 | {
|
826 | 820 | // type
|
827 |
| - if (version is OpenApiSpecVersion.OpenApi3_0) |
| 821 | + if (version is OpenApiSpecVersion.OpenApi2_0 || version is OpenApiSpecVersion.OpenApi3_0) |
828 | 822 | {
|
829 |
| - DowncastTypeArrayToV2OrV3(array, writer, OpenApiSpecVersion.OpenApi3_0); |
| 823 | + DowncastTypeArrayToV2OrV3(type, writer, version, flagsCount); |
830 | 824 | }
|
831 | 825 | else
|
832 | 826 | {
|
833 |
| - writer.WriteOptionalCollection(OpenApiConstants.Type, (string[])Type, (w, s) => w.WriteRaw(s)); |
| 827 | + var list = new List<JsonSchemaType>(); |
| 828 | + foreach (JsonSchemaType flag in System.Enum.GetValues(typeof(JsonSchemaType))) |
| 829 | + { |
| 830 | + list.Add(flag); |
| 831 | + } |
| 832 | + |
| 833 | + writer.WriteOptionalCollection(OpenApiConstants.Type, list, (w, s) => w.WriteRaw(OpenApiTypeMapper.ToIdentifier(s))); |
834 | 834 | }
|
835 | 835 | }
|
836 | 836 | }
|
837 | 837 |
|
838 |
| - private object DeepCloneType(object type) |
| 838 | + private static int CountEnumSetFlags(JsonSchemaType? schemaType) |
839 | 839 | {
|
840 |
| - if (type == null) |
841 |
| - return null; |
| 840 | + int count = 0; |
842 | 841 |
|
843 |
| - if (type is string) |
| 842 | + if(schemaType != null) |
844 | 843 | {
|
845 |
| - return type; // Return the string as is |
846 |
| - } |
| 844 | + // Check each flag in the enum |
| 845 | + foreach (JsonSchemaType value in System.Enum.GetValues(typeof(JsonSchemaType))) |
| 846 | + { |
| 847 | + // Ignore the None flag and check if the flag is set |
| 848 | + if (value != JsonSchemaType.Any && (schemaType & value) == value) |
| 849 | + { |
| 850 | + count++; |
| 851 | + } |
| 852 | + } |
| 853 | + } |
| 854 | + |
| 855 | + return count; |
| 856 | + } |
847 | 857 |
|
848 |
| - if (type is Array array) |
| 858 | + private void UpCastSchemaTypeToV31(JsonSchemaType? type, IOpenApiWriter writer) |
| 859 | + { |
| 860 | + // create a new array and insert the type and "null" as values |
| 861 | + Type = type | JsonSchemaType.Null; |
| 862 | + var list = new List<string>(); |
| 863 | + foreach (JsonSchemaType flag in System.Enum.GetValues(typeof(JsonSchemaType))) |
849 | 864 | {
|
850 |
| - Type elementType = type.GetType().GetElementType(); |
851 |
| - Array copiedArray = Array.CreateInstance(elementType, array.Length); |
852 |
| - for (int i = 0; i < array?.Length; i++) |
| 865 | + // Check if the flag is set in 'type' using a bitwise AND operation |
| 866 | + if ((Type & flag) == flag && flag != JsonSchemaType.Any) |
853 | 867 | {
|
854 |
| - copiedArray.SetValue(DeepCloneType(array?.GetValue(i)), i); |
| 868 | + list.Add(OpenApiTypeMapper.ToIdentifier(flag)); |
855 | 869 | }
|
856 |
| - return copiedArray; |
857 | 870 | }
|
858 | 871 |
|
859 |
| - return null; |
| 872 | + writer.WriteOptionalCollection(OpenApiConstants.Type, list, (w, s) => w.WriteRaw(s)); |
860 | 873 | }
|
861 | 874 |
|
862 |
| - private void DowncastTypeArrayToV2OrV3(string[] array, IOpenApiWriter writer, OpenApiSpecVersion version) |
| 875 | + private void DowncastTypeArrayToV2OrV3(JsonSchemaType? schemaType, IOpenApiWriter writer, OpenApiSpecVersion version, int flagsCount) |
863 | 876 | {
|
864 | 877 | /* If the array has one non-null value, emit Type as string
|
865 | 878 | * If the array has one null value, emit x-nullable as true
|
866 | 879 | * If the array has two values, one null and one non-null, emit Type as string and x-nullable as true
|
867 | 880 | * If the array has more than two values or two non-null values, do not emit type
|
868 | 881 | * */
|
869 | 882 |
|
870 |
| - var nullableProp = version.Equals(OpenApiSpecVersion.OpenApi2_0) |
| 883 | + var nullableProp = version.Equals(OpenApiSpecVersion.OpenApi2_0) |
871 | 884 | ? OpenApiConstants.NullableExtension
|
872 | 885 | : OpenApiConstants.Nullable;
|
873 | 886 |
|
874 |
| - if (array.Length is 1) |
| 887 | + if (flagsCount is 1) |
875 | 888 | {
|
876 |
| - var value = array[0]; |
877 |
| - if (value is OpenApiConstants.Null) |
| 889 | + if (schemaType is JsonSchemaType.Null) |
878 | 890 | {
|
879 | 891 | writer.WriteProperty(nullableProp, true);
|
880 | 892 | }
|
881 | 893 | else
|
882 | 894 | {
|
883 |
| - writer.WriteProperty(OpenApiConstants.Type, value); |
| 895 | + writer.WriteProperty(OpenApiConstants.Type, OpenApiTypeMapper.ToIdentifier(schemaType)); |
884 | 896 | }
|
885 | 897 | }
|
886 |
| - else if (array.Length is 2 && array.Contains(OpenApiConstants.Null)) |
| 898 | + else if (flagsCount is 2 && (schemaType & JsonSchemaType.Null) == JsonSchemaType.Null) |
887 | 899 | {
|
888 |
| - // Find the non-null value and write it out |
889 |
| - var nonNullValue = array.First(v => v != OpenApiConstants.Null); |
890 |
| - writer.WriteProperty(OpenApiConstants.Type, nonNullValue); |
| 900 | + foreach (JsonSchemaType flag in System.Enum.GetValues(typeof(JsonSchemaType))) |
| 901 | + { |
| 902 | + // Skip if the flag is not set or if it's the Null flag |
| 903 | + if ((schemaType & flag) == flag && flag != JsonSchemaType.Null && flag != JsonSchemaType.Any) |
| 904 | + { |
| 905 | + // Write the non-null flag value to the writer |
| 906 | + writer.WriteProperty(OpenApiConstants.Type, OpenApiTypeMapper.ToIdentifier(flag)); |
| 907 | + } |
| 908 | + } |
891 | 909 | if (!Nullable)
|
892 | 910 | {
|
893 | 911 | writer.WriteProperty(nullableProp, true);
|
|
0 commit comments