This repository was archived by the owner on Nov 16, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 35
/
Copy pathTypeExtensions.cs
192 lines (173 loc) · 9.17 KB
/
TypeExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Microsoft.OpenApi.Models;
namespace Microsoft.OpenApi.CSharpAnnotations.DocumentGeneration.Extensions
{
/// <summary>
/// Extension methods for <see cref="Type"/>.
/// </summary>
public static class TypeExtensions
{
private static readonly Dictionary<Type, Func<OpenApiSchema>> _simpleTypeToOpenApiSchema =
new Dictionary<Type, Func<OpenApiSchema>>
{
[typeof(bool)] = () => new OpenApiSchema {Type = "boolean"},
[typeof(byte)] = () => new OpenApiSchema {Type = "string", Format = "byte"},
[typeof(int)] = () => new OpenApiSchema {Type = "integer", Format = "int32"},
[typeof(uint)] = () => new OpenApiSchema {Type = "integer", Format = "int32"},
[typeof(ushort)] = () => new OpenApiSchema { Type = "integer", Format = "int32" },
[typeof(long)] = () => new OpenApiSchema {Type = "integer", Format = "int64"},
[typeof(ulong)] = () => new OpenApiSchema {Type = "integer", Format = "int64"},
[typeof(float)] = () => new OpenApiSchema {Type = "number", Format = "float"},
[typeof(double)] = () => new OpenApiSchema {Type = "number", Format = "double"},
[typeof(decimal)] = () => new OpenApiSchema {Type = "number", Format = "double"},
[typeof(DateTime)] = () => new OpenApiSchema {Type = "string", Format = "date-time"},
[typeof(DateTimeOffset)] = () => new OpenApiSchema {Type = "string", Format = "date-time"},
[typeof(TimeSpan)] = () => new OpenApiSchema {Type = "string"},
[typeof(Guid)] = () => new OpenApiSchema {Type = "string", Format = "uuid"},
[typeof(char)] = () => new OpenApiSchema {Type = "string"},
[typeof(bool?)] = () => new OpenApiSchema {Type = "boolean", Nullable = true},
[typeof(byte?)] = () => new OpenApiSchema {Type = "string", Format = "byte", Nullable = true},
[typeof(int?)] = () => new OpenApiSchema {Type = "integer", Format = "int32", Nullable = true},
[typeof(uint?)] = () => new OpenApiSchema {Type = "integer", Format = "int32", Nullable = true},
[typeof(ushort?)] = () => new OpenApiSchema { Type = "integer", Format = "int32", Nullable = true },
[typeof(long?)] = () => new OpenApiSchema {Type = "integer", Format = "int64", Nullable = true},
[typeof(ulong?)] = () => new OpenApiSchema {Type = "integer", Format = "int64", Nullable = true},
[typeof(float?)] = () => new OpenApiSchema {Type = "number", Format = "float", Nullable = true},
[typeof(double?)] = () => new OpenApiSchema {Type = "number", Format = "double", Nullable = true},
[typeof(decimal?)] = () => new OpenApiSchema {Type = "number", Format = "double", Nullable = true},
[typeof(DateTime?)] = () => new OpenApiSchema {Type = "string", Format = "date-time", Nullable = true},
[typeof(DateTimeOffset?)] = () =>
new OpenApiSchema {Type = "string", Format = "date-time", Nullable = true},
[typeof(TimeSpan?)] = () => new OpenApiSchema { Type = "string", Nullable = true },
[typeof(Guid?)] = () => new OpenApiSchema {Type = "string", Format = "uuid", Nullable = true},
[typeof(char?)] = () => new OpenApiSchema {Type = "string", Nullable = true},
// Uri is treated as simple string.
[typeof(Uri)] = () => new OpenApiSchema {Type = "string"},
[typeof(string)] = () => new OpenApiSchema {Type = "string"},
[typeof(object)] = () => new OpenApiSchema {Type = "object"}
};
/// <summary>
/// Gets the base types for the provided type.
/// </summary>
/// <param name="type">The type to fetch base types for.</param>
/// <returns>List of base types.</returns>
public static IList<Type> GetBaseTypes(this Type type)
{
var baseTypes = new List<Type>();
while (type != null && !type.IsSimple())
{
if (type.BaseType != null && !type.BaseType.IsSimple())
{
baseTypes.Add(type.BaseType);
}
type = type.BaseType;
}
return baseTypes;
}
/// <summary>
/// Gets the item type in an array or an IEnumerable.
/// </summary>
/// <param name="type">An array or IEnumerable type to get the item type from.</param>
/// <returns>The type of the item in the array or IEnumerable.</returns>
public static Type GetEnumerableItemType(this Type type)
{
if (type.IsArray)
{
return type.GetElementType();
}
if (typeof(IEnumerable).IsAssignableFrom(type) && type.GetGenericArguments().Any())
{
return type.GetGenericArguments().First();
}
return null;
}
/// <summary>
/// Determines whether the given type implements the given interface type.
/// </summary>
public static bool ImplementInterface(this Type type, Type interfaceType)
{
for (var currentType = type; currentType != null; currentType = currentType.BaseType)
{
IEnumerable<Type> interfaces = currentType.GetInterfaces();
foreach (var i in interfaces)
{
if (i == interfaceType || i != null && i.ImplementInterface(interfaceType))
{
return true;
}
}
}
return false;
}
/// <summary>
/// Determines whether the given type is a dictionary.
/// </summary>
public static bool IsDictionary(this Type type)
{
return type.IsGenericType &&
(typeof(IDictionary<,>).IsAssignableFrom(type.GetGenericTypeDefinition()) ||
typeof(Dictionary<,>).IsAssignableFrom(type.GetGenericTypeDefinition()));
}
/// <summary>
/// Determines whether the given type is enumerable.
/// </summary>
/// <remarks>
/// Even though string is technically an IEnumerable of char, this method will
/// return false for string since it is generally expected to behave like a simple type.
/// </remarks>
public static bool IsEnumerable(this Type type)
{
return type != typeof(string) && (type.IsArray || typeof(IEnumerable).IsAssignableFrom(type));
}
/// <summary>
/// Determines whether the given type is a "simple" type.
/// </summary>
/// <remarks>
/// A simple type is defined to match with what OpenAPI generally recognizes.
/// This includes the so-called C# primitive types and a few other types such as string, DateTime, etc.
/// </remarks>
public static bool IsSimple(this Type type)
{
return _simpleTypeToOpenApiSchema.ContainsKey(type);
}
/// <summary>
/// Maps a simple type to an OpenAPI data type and format.
/// </summary>
/// <param name="type">Simple type.</param>
/// <remarks>
/// All the following types from http://swagger.io/specification/#data-types-12 are supported.
/// Other types including nullables and URL are also supported.
/// Common Name type format Comments
/// =========== ======= ====== =========================================
/// integer integer int32 signed 32 bits
/// long integer int64 signed 64 bits
/// float number float
/// double number double
/// string string [empty]
/// byte string byte base64 encoded characters
/// binary string binary any sequence of octets
/// boolean boolean [empty]
/// date string date As defined by full-date - RFC3339
/// dateTime string date-time As defined by date-time - RFC3339
/// password string password Used to hint UIs the input needs to be obscured.
/// If the type is not recognized as "simple", System.String will be returned.
/// </remarks>
public static OpenApiSchema MapToOpenApiSchema(this Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
return _simpleTypeToOpenApiSchema.TryGetValue(type, out var result)
? result()
: new OpenApiSchema {Type = "string"};
}
}
}