Пример #1
0
        public override OpenApiObject GetCustomOpenApiConfig(LinkGenerator linkGenerator)
        {
            var baseConfig = base.GetCustomOpenApiConfig(linkGenerator);
            var types      = new OpenApiArray();

            if (CanSelectExisting)
            {
                types.Add(new OpenApiObject
                {
                    { "type", new OpenApiString("autocomplete") }, { "label", new OpenApiString("Existing") },
                    { "validation", new OpenApiArray {
                          new OpenApiString("required-from-list")
                      } }
                });
                // types.Add(new OpenApiObject
                // {
                //     {"type", new OpenApiString("select")}, {"label", new OpenApiString("Existing S")},
                //     {"validation", new OpenApiArray {new OpenApiString("required-from-list")}}
                // });
            }

            if (CanAddNewOrEdit)
            {
                types.Add(new OpenApiObject
                {
                    { "type", new OpenApiString("subGroup") }, { "label", new OpenApiString("+ Add new / Edit") },
                    { "keepFieldGroup", new OpenApiBoolean(true) }
                });
            }

            baseConfig["fieldTypes"] = types;

            return(baseConfig);
        }
        private void CreateArrayOrListObject(string name, object value, Type type, Type nestedType,
                                             OpenApiObject openApiObject)
        {
            if (value == null)
            {
                openApiObject.Add(name, new OpenApiNull());
                return;
            }

            var arrayObject = new OpenApiArray();

            foreach (var item in value as IEnumerable)
            {
                if (nestedType.IsSimpleType())
                {
                    var node = CreateOpenApiObject(nestedType, item);
                    arrayObject.Add(node);
                }
                else
                {
                    var arrayItemObject = new OpenApiObject();
                    var properties      = nestedType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
                    foreach (var property in properties)
                    {
                        var nodeValue = property.GetValue(item);
                        ConvertRec(GetName(property.Name), nodeValue, property.PropertyType, arrayItemObject);
                    }

                    arrayObject.Add(arrayItemObject);
                }
            }

            openApiObject.Add(GetName(name), arrayObject);
        }
        private static IOpenApiAny GetTypeNameForExample(IEdmTypeReference edmTypeReference)
        {
            switch (edmTypeReference.TypeKind())
            {
            case EdmTypeKind.Primitive:
                if (edmTypeReference.IsBoolean())
                {
                    return(new OpenApiBoolean(true));
                }
                else
                {
                    return(new OpenApiString(edmTypeReference.AsPrimitive().PrimitiveDefinition().Name));
                }

            case EdmTypeKind.Entity:
            case EdmTypeKind.Complex:
            case EdmTypeKind.Enum:
                OpenApiObject obj = new OpenApiObject();
                obj["@odata.type"] = new OpenApiString(edmTypeReference.FullName());
                return(obj);

            case EdmTypeKind.Collection:
                OpenApiArray      array       = new OpenApiArray();
                IEdmTypeReference elementType = edmTypeReference.AsCollection().ElementType();
                array.Add(GetTypeNameForExample(elementType));
                return(array);

            case EdmTypeKind.Untyped:
            case EdmTypeKind.TypeDefinition:
            case EdmTypeKind.EntityReference:
            default:
                throw new OpenApiException("Not support for the type kind " + edmTypeReference.TypeKind());
            }
        }
Пример #4
0
        public void Apply(OpenApiSchema schema, SchemaFilterContext context)
        {
            var type = context.Type;

            if (type.IsEnum)
            {
                var values   = Enum.GetValues(type);
                var valueArr = new OpenApiArray();

                foreach (var value in values)
                {
                    var item = new OpenApiObject
                    {
                        ["name"]  = new OpenApiString(Enum.GetName(type, value)),
                        ["value"] = new OpenApiString(value.ToString())
                    };

                    valueArr.Add(item);
                }

                schema.Extensions.Add(
                    "x-ms-enum",
                    new OpenApiObject
                {
                    ["name"]          = new OpenApiString(type.Name),
                    ["modelAsString"] = new OpenApiBoolean(true),
                    ["values"]        = valueArr
                }
                    );
            }
        }
        private bool TryParse(JsonElement token, out IOpenApiAny?any)
        {
            any = null;

            switch (token.ValueKind)
            {
            case JsonValueKind.Array:
                var array = new OpenApiArray();

                foreach (var value in token.EnumerateArray())
                {
                    if (TryParse(value, out var child))
                    {
                        array.Add(child);
                    }
                }

                any = array;
                return(true);

            case JsonValueKind.False:
                any = new OpenApiBoolean(false);
                return(true);

            case JsonValueKind.True:
                any = new OpenApiBoolean(true);
                return(true);

            case JsonValueKind.Number:
                any = new OpenApiDouble(token.GetDouble());
                return(true);

            case JsonValueKind.String:
                any = new OpenApiString(token.GetString());
                return(true);

            case JsonValueKind.Object:
                var obj = new OpenApiObject();

                foreach (var child in token.EnumerateObject())
                {
                    if (TryParse(child.Value, out var value))
                    {
                        obj[child.Name] = value;
                    }
                }

                any = obj;
                return(true);

            case JsonValueKind.Null:
            case JsonValueKind.Undefined:
            default:
                return(false);
            }
        }
Пример #6
0
        public override IOpenApiAny ParseIntoAny()
        {
            var array = new OpenApiArray();

            foreach (var node in childNodes)
            {
                array.Add(node.ParseIntoAny());
            }
            return(array);
        }
Пример #7
0
        /// <summary>
        /// Create a <see cref="OpenApiArray"/>
        /// </summary>
        /// <returns>The created Any object.</returns>
        public override IOpenApiAny CreateAny()
        {
            var array = new OpenApiArray();

            foreach (var node in this)
            {
                array.Add(node.CreateAny());
            }

            return(array);
        }
Пример #8
0
        private static IOpenApiAny CreateOpenApiArray(JsonElement jsonElement)
        {
            var openApiArray = new OpenApiArray();

            foreach (var item in jsonElement.EnumerateArray())
            {
                openApiArray.Add(CreateFromJsonElement(item));
            }

            return(openApiArray);
        }
Пример #9
0
        static public IOpenApiAny GetExample(Type parameter, TypeMaps maps, OpenApiComponents components)
        {
            if (components.Schemas.ContainsKey(parameter.Name))
            {
                return(components.Schemas[parameter.Name].Example);
            }

            if (maps.ContainsMap(parameter))
            {
                return(maps.GetMap(parameter).OpenApiExample);
            }
            else if (parameter == typeof(string))
            {
                int randomNum = new Random().Next() % 3;
                var words     = new string[] { "foo", "bar", "baz" };
                return(new OpenApiString(words[randomNum]));
            }
            else if (IsNumericType(parameter))
            {
                int randomNum = new Random().Next() % 400;
                return(new OpenApiInteger(randomNum));
            }
            else if (parameter == typeof(bool))
            {
                int randomNum = new Random().Next() % 1;
                return(new OpenApiBoolean(randomNum == 0));
            }
            else if (parameter.GetInterfaces().Contains(typeof(IEnumerable)))
            {
                var exampleArr = new OpenApiArray();
                int randomNum  = new Random().Next() % 3;
                for (int _ = 0; _ < randomNum + 1; _++)
                {
                    var innerType = parameter.GetElementType() ?? parameter.GenericTypeArguments[0];
                    exampleArr.Add(GetExample(innerType, maps, components));
                }

                return(exampleArr);
            }
            else
            {
                if (parameter.GetProperties().Length == 0)
                {
                    return(new OpenApiNull());
                }
                var example = new OpenApiObject();
                foreach (var prop in parameter.GetProperties())
                {
                    example.Add(prop.Name, GetExample(prop.PropertyType, maps, components));
                }
                return(example);
            }
        }
        /// <inheritdoc/>
        protected override void SetExtensions(OpenApiPathItem item)
        {
            if (!Context.Settings.ShowMsDosGroupPath)
            {
                return;
            }

            IList <ODataPath> samePaths = new List <ODataPath>();

            foreach (var path in Context.AllPaths.Where(p => p.Kind == ODataPathKind.NavigationProperty && p != Path))
            {
                bool lastIsKeySegment = path.LastSegment is ODataKeySegment;
                if (LastSegmentIsKeySegment != lastIsKeySegment)
                {
                    continue;
                }

                ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
                if (NavigationSource != navigationSourceSegment.NavigationSource)
                {
                    continue;
                }

                ODataNavigationPropertySegment npSegment = path.LastSegment as ODataNavigationPropertySegment;
                if (npSegment == null)
                {
                    npSegment = path.Segments[path.Count - 2] as ODataNavigationPropertySegment;
                }
                if (NavigationProperty != npSegment.NavigationProperty)
                {
                    continue;
                }

                samePaths.Add(path);
            }

            if (samePaths.Any())
            {
                OpenApiArray           array    = new OpenApiArray();
                OpenApiConvertSettings settings = Context.Settings.Clone();
                settings.EnableKeyAsSegment = Context.KeyAsSegment;
                foreach (var p in samePaths)
                {
                    array.Add(new OpenApiString(p.GetPathItemName(settings)));
                }

                item.Extensions.Add(Constants.xMsDosGroupPath, array);
            }
        }
Пример #11
0
        private static IOpenApiAny CreateOpenApiArray(JsonElement jsonElement)
        {
            var openApiArray = new OpenApiArray();

            foreach (var item in jsonElement.EnumerateArray())
            {
                var json = item.ValueKind == JsonValueKind.String
                    ? $"\"{item}\""
                    : item.ToString();

                openApiArray.Add(CreateFromJson(json));
            }

            return(openApiArray);
        }
Пример #12
0
        private static IOpenApiAny CreateOpenApiArray(IEnumerable <JsonElement> jsonElements)
        {
            var openApiArray = new OpenApiArray();

            foreach (var jsonElement in jsonElements)
            {
                var json = jsonElement.ValueKind == JsonValueKind.String
                    ? $"\"{jsonElement}\""
                    : jsonElement.ToString();

                openApiArray.Add(CreateFromJson(json));
            }

            return(openApiArray);
        }
        /// <inheritdoc/>
        protected override void SetExtensions(OpenApiPathItem item)
        {
            if (!Context.Settings.ShowMsDosGroupPath)
            {
                return;
            }

            ODataNavigationSourceSegment navigationSourceSegment = Path.FirstSegment as ODataNavigationSourceSegment;
            IEdmNavigationSource         currentNavSource        = navigationSourceSegment.NavigationSource;

            IList <ODataPath> samePaths = new List <ODataPath>();

            foreach (var path in Context.AllPaths.Where(p => p.Kind == ODataPathKind.Operation && p != Path))
            {
                navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
                if (currentNavSource != navigationSourceSegment.NavigationSource)
                {
                    continue;
                }

                ODataOperationSegment operationSegment = path.LastSegment as ODataOperationSegment;
                if (EdmOperation.FullName() != operationSegment.Operation.FullName())
                {
                    continue;
                }

                samePaths.Add(path);
            }

            if (samePaths.Any())
            {
                OpenApiArray           array    = new OpenApiArray();
                OpenApiConvertSettings settings = Context.Settings.Clone();
                settings.EnableKeyAsSegment = Context.KeyAsSegment;
                foreach (var p in samePaths)
                {
                    array.Add(new OpenApiString(p.GetPathItemName(settings)));
                }

                item.Extensions.Add(Constants.xMsDosGroupPath, array);
            }

            base.SetExtensions(item);
            item.Extensions.AddCustomAtributesToExtensions(Context, EdmOperation);
        }
        private void Transform(string key, OpenApiSchema schema, OpenApiObject openApiObject)
        {
            var type   = schema.Type;
            var format = schema.Format;

            if (type == "object")
            {
                var item = new OpenApiObject();
                foreach (var(itemKey, itemProperty) in schema.Properties)
                {
                    Transform(itemKey, itemProperty, item);
                }

                openApiObject.Add(key, item);
            }

            else if (type == "array")
            {
                if (schema.Items.Type == "object")
                {
                    var item = new OpenApiObject();
                    foreach (var(itemKey, itemProperty) in schema.Items.Properties)
                    {
                        Transform(itemKey, itemProperty, item);
                    }

                    var items = new OpenApiArray {
                        item
                    };
                    openApiObject.Add(key, items);
                }
                else
                {
                    var items = new OpenApiArray();
                    var item  = GetOpenApiValue(schema.Items);
                    items.Add(item);
                    openApiObject.Add(key, items);
                }
            }
            else
            {
                var openApiValue = GetOpenApiValue(schema);
                openApiObject.Add(key, openApiValue);
            }
        }
        private static IOpenApiAny GetTypeNameForExample(ODataContext context, IEdmTypeReference edmTypeReference)
        {
            switch (edmTypeReference.TypeKind())
            {
            case EdmTypeKind.Primitive:
                IEdmPrimitiveType primitiveType = edmTypeReference.AsPrimitive().PrimitiveDefinition();
                OpenApiSchema     schema        = context.CreateSchema(primitiveType);

                if (edmTypeReference.IsBoolean())
                {
                    return(new OpenApiBoolean(true));
                }
                else
                {
                    if (schema.Reference != null)
                    {
                        return(new OpenApiString(schema.Reference.Id));
                    }
                    else
                    {
                        return(new OpenApiString(schema.Type ?? schema.Format));
                    }
                }

            case EdmTypeKind.Entity:
            case EdmTypeKind.Complex:
            case EdmTypeKind.Enum:
                OpenApiObject obj = new OpenApiObject();
                obj[Constants.OdataType] = new OpenApiString(edmTypeReference.FullName());
                return(obj);

            case EdmTypeKind.Collection:
                OpenApiArray      array       = new OpenApiArray();
                IEdmTypeReference elementType = edmTypeReference.AsCollection().ElementType();
                array.Add(GetTypeNameForExample(context, elementType));
                return(array);

            case EdmTypeKind.Untyped:
            case EdmTypeKind.TypeDefinition:
            case EdmTypeKind.EntityReference:
            default:
                throw new OpenApiException("Not support for the type kind " + edmTypeReference.TypeKind());
            }
        }
Пример #16
0
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            var authAttributes = context.MethodInfo.DeclaringType.GetCustomAttributes(true)
                                 .Union(context.MethodInfo.GetCustomAttributes(true))
                                 .OfType <RapiDocLabelAttribute>();

            if (authAttributes.Any())
            {
                var openapiArray = new OpenApiArray();
                foreach (var item in authAttributes)
                {
                    openapiArray.Add(new OpenApiObject
                    {
                        ["color"] = new OpenApiString(item.Color.ToString().ToLower().Replace("_", "-")),
                        ["label"] = new OpenApiString(item.Label)
                    });
                }
                operation.Extensions.Add("x-badges", openapiArray);
            }
            ;
        }
Пример #17
0
        private static void SetEnumExtensionValues(OpenApiSchema schema, Type type)
        {
            var enumValues          = Enum.GetValues(type);
            var enumExtensionValues = new OpenApiArray();

            foreach (var enumValue in enumValues)
            {
                var item = new OpenApiObject
                {
                    ["name"]  = new OpenApiString(Enum.GetName(type, enumValue)),
                    ["value"] = new OpenApiString(enumValue.GetHashCode().ToString())
                };

                enumExtensionValues.Add(item);
            }

            schema.Extensions.Add("x_ms_enum",
                                  new OpenApiObject
            {
                ["values"] = enumExtensionValues
            }
                                  );
        }
        private static IOpenApiAny GetTypeNameForExample(IEdmTypeReference edmTypeReference)
        {
            switch (edmTypeReference.TypeKind())
            {
            case EdmTypeKind.Primitive:
                if (edmTypeReference.IsBinary())
                {
                    // return new OpenApiBinary(new byte[] { 0x00 }); issue on binary writing
                    return(new OpenApiString(Convert.ToBase64String(new byte[] { 0x00 })));
                }
                else if (edmTypeReference.IsBoolean())
                {
                    return(new OpenApiBoolean(true));
                }
                else if (edmTypeReference.IsByte())
                {
                    return(new OpenApiByte(0x00));
                }
                else if (edmTypeReference.IsDate())
                {
                    return(new OpenApiDate(DateTime.MinValue));
                }
                else if (edmTypeReference.IsDateTimeOffset())
                {
                    return(new OpenApiDateTime(DateTimeOffset.MinValue));
                }
                else if (edmTypeReference.IsDecimal() || edmTypeReference.IsDouble())
                {
                    return(new OpenApiDouble(0D));
                }
                else if (edmTypeReference.IsFloating())
                {
                    return(new OpenApiFloat(0F));
                }
                else if (edmTypeReference.IsGuid())
                {
                    return(new OpenApiString(Guid.Empty.ToString()));
                }
                else if (edmTypeReference.IsInt16() || edmTypeReference.IsInt32())
                {
                    return(new OpenApiInteger(0));
                }
                else if (edmTypeReference.IsInt64())
                {
                    return(new OpenApiLong(0L));
                }
                else
                {
                    return(new OpenApiString(edmTypeReference.AsPrimitive().PrimitiveDefinition().Name));
                }

            case EdmTypeKind.Entity:
            case EdmTypeKind.Complex:
            case EdmTypeKind.Enum:
                OpenApiObject obj = new OpenApiObject();
                obj["@odata.type"] = new OpenApiString(edmTypeReference.FullName());
                return(obj);

            case EdmTypeKind.Collection:
                OpenApiArray      array       = new OpenApiArray();
                IEdmTypeReference elementType = edmTypeReference.AsCollection().ElementType();
                array.Add(GetTypeNameForExample(elementType));
                return(array);

            case EdmTypeKind.TypeDefinition:
                var typedef = edmTypeReference.AsTypeDefinition().TypeDefinition();
                return(GetTypeNameForExample(new EdmPrimitiveTypeReference(typedef.UnderlyingType, edmTypeReference.IsNullable)));

            case EdmTypeKind.Untyped:
            case EdmTypeKind.EntityReference:
            default:
                throw new OpenApiException("Not support for the type kind " + edmTypeReference.TypeKind());
            }
        }
Пример #19
0
        /// <summary>
        /// Converts the <see cref="OpenApiString"/>s in the given <see cref="IOpenApiAny"/>
        /// into the appropriate <see cref="IOpenApiPrimitive"/> type based on the given <see cref="OpenApiSchema"/>.
        /// For those strings that the schema does not specify the type for, convert them into
        /// the most specific type based on the value.
        /// </summary>
        public static IOpenApiAny GetSpecificOpenApiAny(IOpenApiAny openApiAny, OpenApiSchema schema)
        {
            if (openApiAny is OpenApiArray openApiArray)
            {
                var newArray = new OpenApiArray();
                foreach (var element in openApiArray)
                {
                    newArray.Add(GetSpecificOpenApiAny(element, schema?.Items));
                }

                return(newArray);
            }

            if (openApiAny is OpenApiObject openApiObject)
            {
                var newObject = new OpenApiObject();

                foreach (var key in openApiObject.Keys.ToList())
                {
                    if (schema != null && schema.Properties != null && schema.Properties.ContainsKey(key))
                    {
                        newObject[key] = GetSpecificOpenApiAny(openApiObject[key], schema.Properties[key]);
                    }
                    else
                    {
                        newObject[key] = GetSpecificOpenApiAny(openApiObject[key], schema?.AdditionalProperties);
                    }
                }

                return(newObject);
            }

            if (!(openApiAny is OpenApiString))
            {
                return(openApiAny);
            }

            if (schema?.Type == null)
            {
                return(GetSpecificOpenApiAny(openApiAny));
            }

            var type   = schema.Type;
            var format = schema.Format;

            var value = ((OpenApiString)openApiAny).Value;

            if (value == null || value == "null")
            {
                return(new OpenApiNull());
            }

            if (type == "integer" && format == "int32")
            {
                if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
                {
                    return(new OpenApiInteger(intValue));
                }
            }

            if (type == "integer" && format == "int64")
            {
                if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var longValue))
                {
                    return(new OpenApiLong(longValue));
                }
            }

            if (type == "integer")
            {
                if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
                {
                    return(new OpenApiInteger(intValue));
                }
            }

            if (type == "number" && format == "float")
            {
                if (float.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var floatValue))
                {
                    return(new OpenApiFloat(floatValue));
                }
            }

            if (type == "number" && format == "double")
            {
                if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
                {
                    return(new OpenApiDouble(doubleValue));
                }
            }

            if (type == "number")
            {
                if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
                {
                    return(new OpenApiDouble(doubleValue));
                }
            }

            if (type == "string" && format == "byte")
            {
                if (byte.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var byteValue))
                {
                    return(new OpenApiByte(byteValue));
                }
            }

            // TODO: Parse byte array to OpenApiBinary type.

            if (type == "string" && format == "date")
            {
                if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateValue))
                {
                    return(new OpenApiDate(dateValue.Date));
                }
            }

            if (type == "string" && format == "date-time")
            {
                if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
                {
                    return(new OpenApiDateTime(dateTimeValue));
                }
            }

            if (type == "string" && format == "password")
            {
                return(new OpenApiPassword(value));
            }

            if (type == "string")
            {
                return(new OpenApiString(value));
            }

            if (type == "boolean")
            {
                if (bool.TryParse(value, out var booleanValue))
                {
                    return(new OpenApiBoolean(booleanValue));
                }
            }

            // If data conflicts with the given type, return a string.
            // This converter is used in the parser, so it does not perform any validations,
            // but the validator can be used to validate whether the data and given type conflicts.
            return(new OpenApiString(value));
        }
Пример #20
0
        /// <summary>
        /// Converts the <see cref="OpenApiString"/>s in the given <see cref="IOpenApiAny"/>
        /// into the most specific <see cref="IOpenApiPrimitive"/> type based on the value.
        /// </summary>
        public static IOpenApiAny GetSpecificOpenApiAny(IOpenApiAny openApiAny)
        {
            if (openApiAny is OpenApiArray openApiArray)
            {
                var newArray = new OpenApiArray();
                foreach (var element in openApiArray)
                {
                    newArray.Add(GetSpecificOpenApiAny(element));
                }

                return(newArray);
            }

            if (openApiAny is OpenApiObject openApiObject)
            {
                var newObject = new OpenApiObject();

                foreach (var key in openApiObject.Keys.ToList())
                {
                    newObject[key] = GetSpecificOpenApiAny(openApiObject[key]);
                }

                return(newObject);
            }

            if (!(openApiAny is OpenApiString))
            {
                return(openApiAny);
            }

            var value = ((OpenApiString)openApiAny).Value;

            if (value == null || value == "null")
            {
                return(new OpenApiNull());
            }

            if (value == "true")
            {
                return(new OpenApiBoolean(true));
            }

            if (value == "false")
            {
                return(new OpenApiBoolean(false));
            }

            if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
            {
                return(new OpenApiInteger(intValue));
            }

            if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var longValue))
            {
                return(new OpenApiLong(longValue));
            }

            if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
            {
                return(new OpenApiDouble(doubleValue));
            }

            if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
            {
                return(new OpenApiDateTime(dateTimeValue));
            }

            // if we can't identify the type of value, return it as string.
            return(new OpenApiString(value));
        }
Пример #21
0
        /// <summary>
        /// Converts the <see cref="OpenApiString"/>s in the given <see cref="IOpenApiAny"/>
        /// into the appropriate <see cref="IOpenApiPrimitive"/> type based on the given <see cref="OpenApiSchema"/>.
        /// For those strings that the schema does not specify the type for, convert them into
        /// the most specific type based on the value.
        /// </summary>
        public static IOpenApiAny GetSpecificOpenApiAny(IOpenApiAny openApiAny, OpenApiSchema schema = null)
        {
            if (openApiAny is OpenApiArray openApiArray)
            {
                var newArray = new OpenApiArray();
                foreach (var element in openApiArray)
                {
                    newArray.Add(GetSpecificOpenApiAny(element, schema?.Items));
                }

                return(newArray);
            }

            if (openApiAny is OpenApiObject openApiObject)
            {
                var newObject = new OpenApiObject();

                foreach (var key in openApiObject.Keys.ToList())
                {
                    if (schema?.Properties != null && schema.Properties.TryGetValue(key, out var property))
                    {
                        newObject[key] = GetSpecificOpenApiAny(openApiObject[key], property);
                    }
                    else
                    {
                        newObject[key] = GetSpecificOpenApiAny(openApiObject[key], schema?.AdditionalProperties);
                    }
                }

                return(newObject);
            }

            if (!(openApiAny is OpenApiString))
            {
                return(openApiAny);
            }

            var value  = ((OpenApiString)openApiAny).Value;
            var type   = schema?.Type;
            var format = schema?.Format;

            if (((OpenApiString)openApiAny).IsExplicit())
            {
                // More narrow type detection for explicit strings, only check types that are passed as strings
                if (schema == null)
                {
                    if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
                    {
                        return(new OpenApiDateTime(dateTimeValue));
                    }
                }
                else if (type == "string")
                {
                    if (format == "byte")
                    {
                        try
                        {
                            return(new OpenApiByte(Convert.FromBase64String(value)));
                        }
                        catch (FormatException)
                        { }
                    }

                    if (format == "binary")
                    {
                        try
                        {
                            return(new OpenApiBinary(Encoding.UTF8.GetBytes(value)));
                        }
                        catch (EncoderFallbackException)
                        { }
                    }

                    if (format == "date")
                    {
                        if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateValue))
                        {
                            return(new OpenApiDate(dateValue.Date));
                        }
                    }

                    if (format == "date-time")
                    {
                        if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
                        {
                            return(new OpenApiDateTime(dateTimeValue));
                        }
                    }

                    if (format == "password")
                    {
                        return(new OpenApiPassword(value));
                    }
                }

                return(openApiAny);
            }

            if (value == null || value == "null")
            {
                return(new OpenApiNull());
            }

            if (schema?.Type == null)
            {
                if (value == "true")
                {
                    return(new OpenApiBoolean(true));
                }

                if (value == "false")
                {
                    return(new OpenApiBoolean(false));
                }

                if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
                {
                    return(new OpenApiInteger(intValue));
                }

                if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var longValue))
                {
                    return(new OpenApiLong(longValue));
                }

                if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
                {
                    return(new OpenApiDouble(doubleValue));
                }

                if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
                {
                    return(new OpenApiDateTime(dateTimeValue));
                }
            }
            else
            {
                if (type == "integer" && format == "int32")
                {
                    if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
                    {
                        return(new OpenApiInteger(intValue));
                    }
                }

                if (type == "integer" && format == "int64")
                {
                    if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var longValue))
                    {
                        return(new OpenApiLong(longValue));
                    }
                }

                if (type == "integer")
                {
                    if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
                    {
                        return(new OpenApiInteger(intValue));
                    }
                }

                if (type == "number" && format == "float")
                {
                    if (float.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var floatValue))
                    {
                        return(new OpenApiFloat(floatValue));
                    }
                }

                if (type == "number" && format == "double")
                {
                    if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
                    {
                        return(new OpenApiDouble(doubleValue));
                    }
                }

                if (type == "number")
                {
                    if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
                    {
                        return(new OpenApiDouble(doubleValue));
                    }
                }

                if (type == "string" && format == "byte")
                {
                    try
                    {
                        return(new OpenApiByte(Convert.FromBase64String(value)));
                    }
                    catch (FormatException)
                    { }
                }

                // binary
                if (type == "string" && format == "binary")
                {
                    try
                    {
                        return(new OpenApiBinary(Encoding.UTF8.GetBytes(value)));
                    }
                    catch (EncoderFallbackException)
                    { }
                }

                if (type == "string" && format == "date")
                {
                    if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateValue))
                    {
                        return(new OpenApiDate(dateValue.Date));
                    }
                }

                if (type == "string" && format == "date-time")
                {
                    if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
                    {
                        return(new OpenApiDateTime(dateTimeValue));
                    }
                }

                if (type == "string" && format == "password")
                {
                    return(new OpenApiPassword(value));
                }

                if (type == "string")
                {
                    return(openApiAny);
                }

                if (type == "boolean")
                {
                    if (bool.TryParse(value, out var booleanValue))
                    {
                        return(new OpenApiBoolean(booleanValue));
                    }
                }
            }

            // If data conflicts with the given type, return a string.
            // This converter is used in the parser, so it does not perform any validations,
            // but the validator can be used to validate whether the data and given type conflicts.
            return(openApiAny);
        }
        public static IOpenApiAny Resolve(IOpenApiAny any, OpenApiSchema schema = null)
        {
            if (any is OpenApiArray arrayAny)
            {
                var newArray = new OpenApiArray();
                foreach (var element in arrayAny)
                {
                    newArray.Add(Resolve(element, schema?.Items));
                }
                return(newArray);
            }
            if (any is OpenApiObject objectAny)
            {
                var newObject = new OpenApiObject();
                foreach (var propertyName in objectAny.Keys.ToList())
                {
                    if (schema?.Properties != null && schema.Properties.ContainsKey(propertyName))
                    {
                        newObject[propertyName] = Resolve(objectAny[propertyName], schema.Properties[propertyName]);
                    }
                    else if (schema?.AdditionalProperties != null && schema.AdditionalProperties is OpenApiSchema ss)
                    {
                        newObject[propertyName] = Resolve(objectAny[propertyName], ss);
                    }
                }
                return(newObject);
            }

            if (!(any is OpenApiString))
            {
                return(any); // already a non-string OpenApiAny
            }
            var value = ((OpenApiString)any).Value;

            if (((OpenApiString)any).Quoted) // quoted string
            {
                if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
                {
                    return(new OpenApiDateTime(dateTimeValue));
                }

                return(any); // actual type is OpenApiString
            }
            if (value == null)
            {
                return(new OpenApiNull());
            }
            if (schema?.Type == null)
            {
                if (value == "true")
                {
                    return(new OpenApiBoolean(true));
                }
                if (value == "false")
                {
                    return(new OpenApiBoolean(false));
                }
                if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
                {
                    return(new OpenApiInt32(intValue));
                }

                if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var longValue))
                {
                    return(new OpenApiInt64(longValue));
                }

                if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
                {
                    return(new OpenApiDouble(doubleValue));
                }

                if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
                {
                    return(new OpenApiDateTime(dateTimeValue));
                }
            }
            else
            {
                if (schema.Type == "integer")
                {
                    if (schema.Format != null && schema.Format == "int64")
                    {
                        if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var longValue))
                        {
                            return(new OpenApiInt64(longValue));
                        }
                    }
                    else
                    {
                        if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
                        {
                            return(new OpenApiInt32(intValue));
                        }
                    }
                }
                if (schema.Type == "number")
                {
                    if (schema.Format != null && schema.Format == "float")
                    {
                        if (float.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var floatValue))
                        {
                            return(new OpenApiFloat(floatValue));
                        }
                    }
                    else
                    {
                        if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
                        {
                            return(new OpenApiDouble(doubleValue));
                        }
                    }
                }
                if (schema.Type == "string")
                {
                    if (schema.Format != null && schema.Format == "byte")
                    {
                        try
                        {
                            return(new OpenApiByte(Convert.FromBase64String(value)));
                        }
                        catch (FormatException)
                        { }
                    }
                    else if (schema.Format != null && schema.Format == "binary")
                    {
                        try
                        {
                            return(new OpenApiBinary(Encoding.UTF8.GetBytes(value)));
                        }
                        catch (EncoderFallbackException)
                        { }
                    }
                    else if (schema.Format != null && (schema.Format == "date" || schema.Format == "date-time"))
                    {
                        if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateValue))
                        {
                            return(new OpenApiDate(dateValue.Date));
                        }
                    }
                    else if (schema.Format != null && schema.Format == "password")
                    {
                        return(new OpenApiPassword(value));
                    }
                    else
                    {
                        return(new OpenApiString(value));
                    }
                }
                if (schema.Type == "boolean")
                {
                    if (bool.TryParse(value, out var booleanValue))
                    {
                        return(new OpenApiBoolean(booleanValue));
                    }
                }
            }
            return(any);
        }
        /// <summary>
        /// Finds the existing reference object based on the key from the input or creates a new one.
        /// </summary>
        /// <returns>The existing or created reference object.</returns>
        internal override OpenApiSchema FindOrAddReference(Type input)
        {
            // Return empty schema when the type does not have a name.
            // This can occur, for example, when a generic type without the generic argument specified
            // is passed in.
            if (input == null || input.FullName == null)
            {
                return(new OpenApiSchema());
            }

            var key = GetKey(input);

            // If the schema already exists in the References, simply return.
            if (References.ContainsKey(key))
            {
                return(new OpenApiSchema
                {
                    Reference = new OpenApiReference
                    {
                        Id = key,
                        Type = ReferenceType.Schema
                    }
                });
            }

            try
            {
                // There are multiple cases for input types that should be handled differently to match the OpenAPI spec.
                //
                // 1. Simple Type
                // 2. Enum Type
                // 3. Dictionary Type
                // 4. Enumerable Type
                // 5. Object Type
                var schema = new OpenApiSchema();

                if (input.IsSimple())
                {
                    schema = input.MapToOpenApiSchema();

                    // Certain simple types yield more specific information.
                    if (input == typeof(char))
                    {
                        schema.MinLength = 1;
                        schema.MaxLength = 1;
                    }
                    else if (input == typeof(Guid))
                    {
                        schema.Example = new OpenApiString(Guid.Empty.ToString());
                    }

                    return(schema);
                }

                if (input == typeof(Stream) || input.BaseType == typeof(Stream))
                {
                    schema.Type   = "string";
                    schema.Format = "binary";

                    return(schema);
                }

                if (input.IsEnum)
                {
                    var enumValues    = Enum.GetValues(input);
                    var xEnumVarNames = new OpenApiArray();

                    foreach (var enumValue in enumValues)
                    {
                        var enumName = Enum.GetName(input, enumValue);
                        if (schema.Type == null)
                        {
                            if (Enum.GetUnderlyingType(input).ToString() == "System.Int32")
                            {
                                schema.Type   = "integer";
                                schema.Format = "int32";
                            }
                            else
                            {
                                schema.Type = "string";
                            }
                        }

                        if (schema.Type == "integer")
                        {
                            schema.Enum.Add(new OpenApiInteger((int)enumValue));
                            xEnumVarNames.Add(new OpenApiString(enumName));
                        }
                        else
                        {
                            schema.Enum.Add(new OpenApiString(enumName));
                        }
                    }

                    if (xEnumVarNames.Count > 0)
                    {
                        schema.Extensions.Add("x-enum-varnames", xEnumVarNames);
                    }

                    return(schema);
                }

                if (input.IsDictionary())
                {
                    schema.Type = "object";
                    schema.AdditionalProperties = FindOrAddReference(input.GetGenericArguments()[1]);

                    return(schema);
                }

                if (input.IsEnumerable())
                {
                    schema.Type = "array";

                    schema.Items = FindOrAddReference(input.GetEnumerableItemType());

                    return(schema);
                }

                var nullableUnderlyingType = Nullable.GetUnderlyingType(input);

                if (nullableUnderlyingType?.IsEnum == true)
                {
                    schema.Type     = "string";
                    schema.Nullable = true;

                    foreach (var name in nullableUnderlyingType.GetEnumNames())
                    {
                        schema.Enum.Add(new OpenApiString(name));
                    }

                    return(schema);
                }

                schema.Type = "object";

                // Note this assignment is necessary to allow self-referencing type to finish
                // without causing stack overflow.
                // We can also assume that the schema is an object type at this point.
                References[key] = schema;

                var propertyNameDeclaringTypeMap = new Dictionary <string, Type>();
                var typeAttributes = input.GetCustomAttributes(false);

                foreach (var typeAttribute in typeAttributes)
                {
                    if (typeAttribute.GetType().FullName == "Newtonsoft.Json.JsonObjectAttribute")
                    {
                        var type = typeAttribute.GetType();
                        var namingStrategyInfo = type.GetProperty("NamingStrategyType");
                        if (namingStrategyInfo != null)
                        {
                            var namingStrategyValue = namingStrategyInfo.GetValue(typeAttribute, null);

                            if (namingStrategyValue?.ToString()
                                == "Newtonsoft.Json.Serialization.CamelCaseNamingStrategy")
                            {
                                _propertyNameResolver = new CamelCasePropertyNameResolver();
                            }
                        }
                    }
                }

                var a = input.FullName;

                foreach (var propertyInfo in input.GetProperties())
                {
                    var ignoreProperty = false;

                    var innerSchema = FindOrAddReference(propertyInfo.PropertyType);

                    var propertyName = _propertyNameResolver.ResolvePropertyName(propertyInfo);

                    // Construct property name like it shows up in documentation xml.
                    var propertyFullName = propertyInfo.DeclaringType.Namespace + "." +
                                           propertyInfo.DeclaringType?.Name + "." + propertyInfo.Name;

                    if (this._propertyDescriptionMap.ContainsKey(propertyFullName))
                    {
                        innerSchema.Description = this._propertyDescriptionMap[propertyFullName];
                    }

                    var attributes = propertyInfo.GetCustomAttributes(false);

                    foreach (var attribute in attributes)
                    {
                        if (attribute.GetType().FullName == "Newtonsoft.Json.JsonPropertyAttribute")
                        {
                            var type = attribute.GetType();
                            var requiredPropertyInfo = type.GetProperty("Required");

                            if (requiredPropertyInfo != null)
                            {
                                var requiredValue = Enum.GetName(
                                    requiredPropertyInfo.PropertyType,
                                    requiredPropertyInfo.GetValue(attribute, null));

                                if (requiredValue == "Always")
                                {
                                    schema.Required.Add(propertyName);
                                }
                            }
                        }

                        if (attribute.GetType().FullName == "Newtonsoft.Json.JsonIgnoreAttribute")
                        {
                            ignoreProperty = true;
                        }
                    }

                    if (ignoreProperty)
                    {
                        continue;
                    }

                    var propertyDeclaringType = propertyInfo.DeclaringType;

                    if (propertyNameDeclaringTypeMap.ContainsKey(propertyName))
                    {
                        var existingPropertyDeclaringType = propertyNameDeclaringTypeMap[propertyName];
                        var duplicateProperty             = true;

                        if (existingPropertyDeclaringType != null && propertyDeclaringType != null)
                        {
                            if (propertyDeclaringType.IsSubclassOf(existingPropertyDeclaringType) ||
                                (existingPropertyDeclaringType.IsInterface &&
                                 propertyDeclaringType.ImplementInterface(existingPropertyDeclaringType)))
                            {
                                // Current property is on a derived class and hides the existing
                                schema.Properties[propertyName] = innerSchema;
                                duplicateProperty = false;
                            }

                            if (existingPropertyDeclaringType.IsSubclassOf(propertyDeclaringType) ||
                                (propertyDeclaringType.IsInterface &&
                                 existingPropertyDeclaringType.ImplementInterface(propertyDeclaringType)))
                            {
                                // current property is hidden by the existing so don't add it
                                continue;
                            }
                        }

                        if (duplicateProperty)
                        {
                            throw new AddingSchemaReferenceFailedException(
                                      key,
                                      string.Format(
                                          SpecificationGenerationMessages.DuplicateProperty,
                                          propertyName,
                                          input));
                        }
                    }

                    schema.Properties[propertyName] = innerSchema;
                    propertyNameDeclaringTypeMap.Add(propertyName, propertyDeclaringType);
                }

                References[key] = schema;

                return(new OpenApiSchema
                {
                    Reference = new OpenApiReference
                    {
                        Id = key,
                        Type = ReferenceType.Schema
                    }
                });
            }
            catch (Exception e)
            {
                // Something went wrong while fetching schema, so remove the key if exists from the references.
                if (References.ContainsKey(key))
                {
                    References.Remove(key);
                }

                throw new AddingSchemaReferenceFailedException(key, e.Message);
            }
        }